/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
 * See LICENSE file for license details.
 */

#include "dat.h"
#include "fns.h"

void
update_rules(Rule **rule, char *data) {
#define putc(m, c) BLOCK(if((m)->pos < (m)->end) *(m)->pos++ = c;)
#define getc(m) ((m)->pos < (m)->end ? *(m)->pos++ : 0)
#define ungetc(m) BLOCK(if((m)->pos > (m)->data) --(m)->pos)

	IxpMsg buf, valuebuf, rebuf;
	Reprog *re;
	Rule *r;
	Ruleval **rvp;
	Ruleval *rv;
	char *w;
	char regexp[256];
	char c;
	int len;

	while((r = *rule)) {
		*rule = r->next;
		while((rv = r->values)) {
			r->values = rv->next;
			free(rv);
		}
		free(r->regex);
		free(r->value);
		free(r);
	}

	if(!data || !data[0])
		return;

	buf = ixp_message(data, strlen(data), MsgUnpack);

begin:
	msg_eatrunes(&buf, isspacerune, true);
	if(getc(&buf) == '/')
		goto regexp;
	/* Regexp not at begining of the line. Rest of the line is junk. */
	while((c = getc(&buf)))
		if(c == '\n')
			goto begin;
	goto done;

regexp:
	rebuf = ixp_message(regexp, sizeof regexp - 1, MsgPack);
	while((c = getc(&buf)))
		if(c == '/')
			goto value;
		else if(c != '\\')
			putc(&rebuf, c);
		else if(buf.pos[1] == '/' || buf.pos[1] == '\\' && buf.pos[2] == '/')
			putc(&rebuf, getc(&buf));
		else {
			putc(&rebuf, c);
			putc(&rebuf, getc(&buf));
		}
	goto done;

value:
	valuebuf = ixp_message(buffer, sizeof buffer - 1, MsgPack);
	while((c = getc(&buf))) {
		if(c == '\n') {
			putc(&valuebuf, ' ');
			msg_eatrunes(&buf, isspacerune, true);
			if((c = getc(&buf)) == '/') {
				ungetc(&buf);
				break;
			}
		}
		putc(&valuebuf, c);
	}

	putc(&rebuf, '\0');
	re = regcomp(regexp);
	if(!re)
		goto begin;
	r = emallocz(sizeof *r);
	*rule = r;
	rule = &r->next;
	r->regex = re;

	valuebuf.end = valuebuf.pos;
	valuebuf.pos = valuebuf.data;
	rvp = &r->values;
	while((w = msg_getword(&valuebuf, 0))) {
		free(r->value);
		r->value = estrdup(w);
		if(strchr(w, '=')) {
			len = strlen(w) + 1;
			*rvp = rv = emallocz(sizeof *rv + len);
			rvp = &rv->next;

			memcpy(&rv[1], w, len);
			tokenize(&rv->key, 2, (char*)&rv[1], '=');
		}
	}
	goto begin;

done:
	return;
}

