/*
**	config.c	- 
**
**
** Copyright (c) 1993-95  David J. Hughes
** Copyright (c) 1995   Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** This software is provided "as is" without any expressed or implied warranty.
**
**
*/



#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>

#include "common/portability.h"
#include "msql.h"



typedef struct {
	char	*handle,
		*charVal;
	int	type,
		intVal;
} Mconf;


Mconf conf_table [] = {
{"msql_user",	"msql",				CHAR_TYPE,	0},
{"admin_user",	"root",				CHAR_TYPE,	0},
{"pid_file",	"%I/msql2.pid",			CHAR_TYPE,	0},
{"inst_dir",	INST_DIR,			CHAR_TYPE,	0},
{"tcp_port",	NULL,				INT_TYPE,	1114},
{"unix_port",	"%I/msql2.sock",		CHAR_TYPE,	0},
{ NULL,		NULL,				0,		0}
};


#define skipWhite(cp) while(*cp=='\t' || *cp==' '){cp++;}
#define getLine(b,s,f)	fgets(b,s,f); curLine++


#define SEC_GENERAL	1
#define SEC_ACL		2
#define SEC_SECURITY	3


char	*strdup();
char	*strtok();

int	curLine = 0;


static char * expandConf(str)
	char	*str;
{
	static	char buf[200];
	char	*cp,*cp2;
	
	bzero(buf,sizeof(buf));
	cp = str;
	cp2 = buf;
	while(*cp)
	{
		if (*cp == '%')
		{
			switch(*(cp+1))
			{
				case 'I':
					strcpy(cp2,msqlGetCharConf("inst_dir"));
					while(*cp2)
						cp2++;
					cp+=2;
					break;

				default:
					*cp2++ = *cp++;
					*cp2++ = *cp++;
					break;
			}
			continue;
		}
		*cp2++ = *cp++;
	}
	return(buf);
}



static void confErr(str)
	char	*str;
{
	fprintf(stderr,"\nConfig Error : %s at line %d\n\n",str,curLine);
	exit(1);
}


static int checkIntVal(str)
	char	*str;
{
	char 	*cp = str;

	while(*cp)
	{
		if (!isdigit(*cp))
			return(-1);
		cp++;
	}
	return(0);
}



static int setConfigEntry(handle,value)
	char	*handle,
		*value;
{
	Mconf	*cur;

	cur = conf_table;
	while(cur->handle)
	{
		if (strcmp(cur->handle,handle) == 0)
		{
			if (cur->type == CHAR_TYPE)
				cur->charVal = (char *)strdup(value);
			else
			{
				if (checkIntVal(value) == 0)
				{
					cur->intVal = atoi(value);
				}
			}
			return(0);
		}
		cur++;
	}
	return(-1);
}



int msqlGetIntConf(handle)
	char	*handle;
{
	Mconf	*cur;

	cur = conf_table;
	while(cur->handle)
	{
		if (strcmp(cur->handle,handle) == 0)
		{
			return(cur->intVal);
		}
		cur++;
	}
	return(-1);
}



char *msqlGetCharConf(handle)
	char	*handle;
{
	Mconf	*cur;

	cur = conf_table;
	while(cur->handle)
	{
		if (strcmp(cur->handle,handle) == 0)
		{
			return(expandConf(cur->charVal));
		}
		cur++;
	}
	return(NULL);
}




static int checkSection(name)
	char	*name;
{
	char *cp;

	cp = name;
	while(*cp)
	{
		*cp = tolower(*cp);
		cp++;
	}
	if (strcmp(name,"general") == 0)
	{
		return(SEC_GENERAL);
	}

	return(-1);
}





static void processDirective(sec, dir, val)
	int	sec;
	char	*dir,
		*val;
{
	char	*cp;

	/*
	** Map to lower case
	*/
	cp = dir;
	while(*cp)
	{
		*cp = tolower(*cp);
		cp++;
	}

	/*
	** Do your thing
	*/
	switch(sec)
	{
		case SEC_GENERAL:
			if (strcmp(dir,"admin_user") == 0 ||
			    strcmp(dir,"msql_user") == 0 ||
			    strcmp(dir,"pid_file") == 0 ||
			    strcmp(dir,"inst_dir") == 0 ||
			    strcmp(dir,"tcp_port") == 0 ||
			    strcmp(dir,"unix_port") == 0)
			{
				setConfigEntry(dir,val);
			}
			else
			{
				confErr("Unknown directive");
			}
			break;
	}
}





int msqlLoadConfigFile(file)
	char	*file;
{
	FILE	*fp;
	char	buf[160],
		*cp,
		*directive,
		*value;
	int	curSection = 0;
	extern	int msqlConfigLoaded;


	/*
	** Find and open the config file
	*/
	msqlConfigLoaded = 1;
	if (file)
		fp = fopen(file,"r");
	else
	{
		sprintf(buf,"%s/msql.conf", INST_DIR);
		fp = fopen(buf,"r");
	}
	if (!fp)
	{
		perror("Failed to open config file");
		return(-1);
	}


	/*
	** Read and parse the file
	*/
	getLine(buf,160,fp);
	while(!feof(fp))
	{
		/*
		** Dodge blanks
		*/
		cp = buf;
		skipWhite(cp);
		if (*cp == '#' || *cp == '\n')
		{
			getLine(buf,160,fp);
			continue;
		}

		/*
		** Look for a start of section
		*/
		if (*cp == '[')
		{
			directive = (char *)strtok(cp+1," \t]");
			curSection = checkSection(directive);
			if(curSection < 0)
			{
				confErr("Bad section name");
			}
			getLine(buf,160,fp);
			continue;
		}

		/*
		** Handle directives
		*/
		if (!curSection)
		{
			confErr("Directive prior to section header");
		}

		directive = (char *)strtok(cp, " \t=");
		value = (char *)strtok(NULL, " =\t\n");

		processDirective(curSection, directive,value);

		getLine(buf,160,fp);
	}
	return(0);
}
