/********************************************************************\
  * BitlBee -- An IRC to other IM-networks gateway                     *
  *                                                                    *
  * Copyright 2002-2008 Wilmer van der Gaast and others                *
  \********************************************************************/

/* INI file reading code						*/

/*
  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 with
  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
  Fifth Floor, Boston, MA  02110-1301  USA
*/
#define BITLBEE_CORE
#include "bitlbee.h"

ini_t *ini_open(char *file)
{
	int fd = -1;
	ini_t *ini = NULL;
	struct stat fi;

	if (file && (fd = open(file, O_RDONLY)) != -1 &&
	    fstat(fd, &fi) == 0 &&
	    fi.st_size <= 16384 &&
	    (ini = g_malloc(sizeof(ini_t) + fi.st_size + 1)) &&
	    read(fd, ini->file, fi.st_size) == fi.st_size) {
		memset(ini, 0, sizeof(ini_t));
		ini->size = fi.st_size;
		ini->file[ini->size] = 0;
		ini->cur = ini->file;
		ini->c_section = "";

		close(fd);

		return ini;
	}

	if (fd >= 0) {
		close(fd);
	}

	ini_close(ini);

	return NULL;
}

/* Strips leading and trailing whitespace and returns a pointer to the first
   non-ws character of the given string. */
static char *ini_strip_whitespace(char *in)
{
	char *e;

	while (g_ascii_isspace(*in)) {
		in++;
	}

	e = in + strlen(in) - 1;
	while (e > in && g_ascii_isspace(*e)) {
		e--;
	}
	e[1] = 0;

	return in;
}

int ini_read(ini_t *file)
{
	char *s;

	while (file->cur && file->cur < file->file + file->size) {
		char *e, *next;

		file->line++;

		/* Find the end of line */
		if ((e = strchr(file->cur, '\n')) != NULL) {
			*e = 0;
			next = e + 1;
		} else {
			/* No more lines. */
			e = file->cur + strlen(file->cur);
			next = NULL;
		}

		/* Comment? */
		if ((s = strchr(file->cur, '#')) != NULL) {
			*s = 0;
		}

		file->cur = ini_strip_whitespace(file->cur);

		if (*file->cur == '[') {
			file->cur++;
			if ((s = strchr(file->cur, ']')) != NULL) {
				*s = 0;
				file->c_section = file->cur;
			}
		} else if ((s = strchr(file->cur, '=')) != NULL) {
			*s = 0;
			file->key = ini_strip_whitespace(file->cur);
			file->value = ini_strip_whitespace(s + 1);

			if ((s = strchr(file->key, '.')) != NULL) {
				*s = 0;
				file->section = file->key;
				file->key = s + 1;
			} else {
				file->section = file->c_section;
			}

			file->cur = next;
			return 1;
		}
		/* else: noise/comment/etc, let's just ignore it. */

		file->cur = next;
	}

	return 0;
}

void ini_close(ini_t *file)
{
	g_free(file);
}
