#ifndef LINT
static char *rcsid="rtconfig.c,v 1.1.1.1 1999/08/12 19:36:45 woods Exp";
#endif

/*
	rtconfig.c,v
	Revision 1.1.1.1  1999/08/12 19:36:45  woods
	whoson version 1.08
	
	Revision 1.5  1998/07/05 00:26:18  crosser
	Change copyright

	Revision 1.4  1998/07/02 18:01:15  crosser
	change error reporting to syslog

	Revision 1.3  1998/07/02 15:51:24  crosser
	change DPRINT

	Revision 1.2  1998/07/01 05:18:09  crosser
	minor warnings fix

	Revision 1.1  1998/07/01 05:01:22  crosser
	Initial revision

*/

/*
	WHAT IS IT:
		Implementation of experimental "whoson" protocol
	AUTHOR:
		Eugene G. Crosser <crosser@average.org>
	COPYRIGHT:
		Public domain
*/

/* whoson runtime configuration parser */

#include "config.h"

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#include "rtconfig.h"
#include "report.h"

struct _servdesc *wso_read_config(char *fn,int do_server) {
	int rc=-1;
	int lineno=0;
	int endfile=0;
	FILE *fp;
	char buf[512];
	char *p,*q=NULL,*v;
	enum {no_entry,client_entry,server_entry} current;
	struct _cfgrec *cfgrec=NULL;
	struct _servdesc *start=NULL,**curr=&start;

	if ((fp=fopen(fn,"r")) == NULL) {
		ERRLOG((LOG_ERR,"[WHOSON] %s open failed: %m",fn))
		return NULL;
	}

	current=no_entry;
	while (!endfile) {
		endfile=(fgets(buf,sizeof(buf)-1,fp) == NULL);
		lineno++;
		buf[sizeof(buf)-1]='\0'; /* paranoia */
		if (!endfile && (buf[strlen(buf)-1] != '\n')) {
			ERRLOG((LOG_ERR,"[WHOSON] %s(%d): line too long\n",fn,lineno))
			rc=-1;
			goto exit;
		}
		if (!endfile) { /* cut off comments */
			if ((q=strchr(buf,'#'))) *q='\0';
			for (q=buf;(*q) && isspace(*q);q++) /*nothing*/;
			if (*q == '\0') continue;
		}

		DPRINT(("New line %d: %s[%sendfile current=%d]\n",
			lineno,buf,endfile?"":"no ",current))

		if ((endfile || !isspace(buf[0])) &&
		    (((current == client_entry) && (!do_server)) ||
		     ((current == server_entry) && (do_server)))) {
			rc=-1;
			if (cfgrec && cfgrec->rtcfg_end && (*curr)) {
				rc=(cfgrec->rtcfg_end)(&((*curr)->priv));
			}
			if (rc) {
				ERRLOG((LOG_ERR,"[WHOSON] %s(%d): previous entry bad\n",
							fn,lineno))
				rc=-1;
				goto exit;
			}
			if (*curr) curr=&((*curr)->next);
			current=no_entry; /* paranoia */
			cfgrec=NULL;
		}
		if (endfile) continue;

		if (isspace(buf[0])) { /* continuation line */
			if (current == no_entry) {
				ERRLOG((LOG_ERR,"[WHOSON] %s(%d): homeless continuation line\n",
							fn,lineno))
				rc=-1;
				goto exit;
			}
			if (((current == client_entry) && (do_server)) ||
			    ((current == server_entry) && (!do_server)))
				continue;
		} else { /* start of entry */
			p=buf;
			while ((*p) && !isspace(*p)) p++;
			if (*p) {
				*p='\0';
				p++;
				while ((*p) && isspace(*p)) p++;
				q=p;
				while ((*q) && !isspace(*q)) q++;
				if (*q) {
					*q='\0';
					q++;
					while ((*q) && isspace(*q)) q++;
				}
			}

			DPRINT(("start entry: buf=%s p=%s q=%s\n",buf,p,q))

			if (strcasecmp(buf,"client") == 0) {
				current=client_entry;
				if (do_server) continue;
				cfgrec=wso_servlist;
			} else if (strcasecmp(buf,"server") == 0) {
				current=server_entry;
				if (!do_server) continue;
				cfgrec=wso_servlist;
			} else {
				ERRLOG((LOG_ERR,"[WHOSON] %s(%d): invalid entry name \"%s\"\n",
							fn,lineno,buf))
				rc=-1;
				goto exit;
			}
			for (;cfgrec->name;cfgrec++) {
				if (strcasecmp(p,cfgrec->name) == 0) break;
			}
			rc=-1;
			if (cfgrec->rtcfg_init) {
				(*curr)=(struct _servdesc*)malloc
					(sizeof(struct _servdesc));
				memset(*curr,0,
					sizeof(struct _servdesc));
				(*curr)->root.init=cfgrec->root.init;
				rc=(cfgrec->rtcfg_init)(&((*curr)->priv));
			}
			if (rc) {
				ERRLOG((LOG_ERR,"[WHOSON] %s(%d): unsupported %s type \"%s\"\n",
							fn,lineno,buf,p))
				goto exit;
			}
		}
		/* parse parameters; 'q' points to the start of params */
		while (*q) {
			p=q;
			while ((*p) && !isspace(*p)) p++;
			if (*p) {
				*p='\0';
				p++;
				while ((*p) && isspace(*p)) p++;
			}
			if ((v=strchr(q,'='))) *v++='\0';
			rc=-1;
			if (cfgrec && cfgrec->rtcfg_next)
				rc=(cfgrec->rtcfg_next)(q,v,&((*curr)->priv));
			if (rc) {
				ERRLOG((LOG_ERR,"[WHOSON] %s(%d): bad key %s=%s\n",
						fn,lineno,q,v?v:"(null)"))
				goto exit;
			}
			q=p;
		}
	}

exit:
	fclose(fp);
	return rc?NULL:start;
}
