#include "global.hh"

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

#include "lineparser.hh"
#include "main.hh"

// better name: Basic Parser

LineParser *lps;

//********************************************************************

LineParser::LineParser ()
{
	line = NULL;
	line_size = 0;
}

LineParser::~LineParser ()
{
	if (line) delete line;
}

int
LineParser::eol ()
{
	if (*p == 0 || *p == '\n')
		return 1;
	else
		return 0;
}

int
LineParser::null ()
{
	if (*p == 0)
		return 1;
	else
		return 0;
}

int
LineParser::get_char (char &c)
{
	if (eol ())
		return 0;
	else
	{
		c = *p;
		p++;
		return 1;
	}
}

int
LineParser::space () {
	return (isspace (*p));
}

int
LineParser::inc (char c) {
	if (*p == c) {
		p++;
		return 1;
	}
	else
		return 0;
}

int
LineParser::inc () {
	if (eol ())
		return 0;
	else {
		p++;
		return 1;
	}
}

int
LineParser::jmp (char c) {
	// jumps to the specified character (or to the end of the line if
	// none found)
	while (*p != c && !eol ()) p++;
}

int
LineParser::skip (const char *list) {
	// skip as much specified characters as possible
	// list - characters to skip
	int i;
	do {
		for (i = 0; list[i] && list[i] != *p; i++);
		if (list[i] == 0) return 0;// last char tried was the end of list = no character matched
	} while (inc ());
}

int
LineParser::skip_space () {
	while (space() && *p != '\n')
		p++;
}

int
LineParser::reset_line () {
	p = line;
	skip_space ();
}

int
LineParser::digit () {
	return (isdigit (*p));
}

int
LineParser::num (int &n) {
	int cr;
	n=0;
	sscanf(p,"%d%n", &n, &cr);
	p+=cr;
}

int
LineParser::num (double &x) {
	int cr;
	x=0.0;
	sscanf(p,"%lf%n", &x, &cr);
	p+=cr;
}

int
LineParser::pos (int &x, int &y, int wd, int ht) {
	skip_space ();

	int a; // align right, bottom (1) or left, top (0)

	if (inc ('c')) {
		int frac=2;
		if (inc ('/') && digit()) num(frac);
		x = root.wd/frac - wd/2;
	}
	else {
		a = 0;
		if (inc ('-')) a = 1;
		inc ('+'); // skip possible sign
		num (x);
		if (a) x = root.wd - wd - x;
	};

	skip_space ();

	if (inc ('c')) {
		int frac=2;
		if (inc ('/') && digit()) num(frac);
		y = root.ht/frac - ht/2;
	}
	else {
		a = 0;
		if (inc ('-')) a = 1;
		inc ('+'); // skip possible sign
		num (y);
		if (a) y = root.ht - ht - y;
	};
}

int
LineParser::geom (int &x, int &y, int &wd, int &ht) {
	// parse extended geometry string
	// extended = 
	// wn on width means display width divided by n (e.g. w3 = disp.wd / 3)
	// hn on height means display height divided by n
	// 'c' in the position part means center
	skip_space ();

	if (inc ('w')) {
		int f = 1;
		if (digit ()) num (f);
		wd = root.wd/f;
	}
	else
		num (wd);

	skip ("x");

	if (inc ('h')) {
		int f = 1;
		if (digit()) num (f);
		ht = root.ht/f;
	}
	else
		num (ht);

	pos (x, y, wd, ht);
}

int
LineParser::match (const char *keyword) {
	int len = strlen (keyword);

	if (strncasecmp (p, keyword, len) == 0) {
		p += len;
		return 1;
	}

	return 0;
}

int
LineParser::match_space (const char *keyword) {
	int len = strlen (keyword);

	if (strncasecmp (p, keyword, len) == 0) {
		p += len;
		if (space () || eol ())	return 1;
		p -= len;
	}

	return 0;
}

int
LineParser::token (char *&r) {
	// copies one token into new string
	// ends with "p" pointing just after the token

	// token is a sequence of chars delimited by spaces (or newlines)
	skip_space ();
	
	char *beg = p;
	while (!space () && !null ()) p++;

	/*
	if (beg == p) {
		r = NULL;
		return 0;
	};
	*/
	
	int len = p - beg;
	r = new char[len + 1];
	strncpy (r, beg, len);
	r[len] = 0;
}

int
LineParser::stripcpy (char *&r) {
	// strips leading spaces and trailing spaces and newlines and copies
	// the result into a new string
	int len;

	skip_space ();
	len = 0;
	while (p[len] != '\n' && p[len] != 0)
		len++;

	while (len>0 && isspace(p[len-1]))
		len--;

	r = new char[len+1];
	strncpy (r, p, len);
	r[len] = 0;
}

int
LineParser::stripcpy2 (char *&r) {
	// strips all data before the first quote and after the second and
	// copy the result in new string
	jmp ('"'); // find the first quote
	inc (); // skip the first quote

	char *beg = p; // beginning of result

	jmp ('"'); // find the second quote

	int len=0;
	len = p - beg;
	r = new char[len+1];
	strncpy (r, beg, len);
	r[len] = 0;

	inc (); // skip the second quote
}

int
LineParser::error (const char *tpl, ...) {
	va_list ap;
		 
	va_start (ap, tpl);
	vfprintf (stderr, tpl, ap);
	va_end (ap);
	fprintf (stderr, "%s", p);
}
