/* Autoconf patching by David Hedbor, neotron@lysator.liu.se */
#include "tintin.h"
#include <ctype.h>
int stacks[100][3];
extern struct listnode *common_myvars;

#ifdef HAVE_UNISTD_H
#include <stdlib.h>
#include <unistd.h>
#endif

extern char *get_arg_in_braces();
extern struct listnode *searchnode_list();

void math_command(line, ses)
     char *line;
     struct session *ses;
{
	struct listnode *my_vars, *ln;
	char left[BUFFER_SIZE], right[BUFFER_SIZE];
	char temp[BUFFER_SIZE], result[BUFFER_SIZE];
	int i;

	my_vars = (ses) ? ses->myvars : common_myvars;
	line = get_arg_in_braces(line, left, 0);
	line = get_arg_in_braces(line, right, 1);
	substitute_vars(right, result);
	substitute_myvars(result, right, ses);
	i = eval_expression(right);
	sprintf(temp, "%d", i);
	if ((ln = searchnode_list(my_vars, left)) != NULL)
		deletenode_list(my_vars, ln);
	insertnode_list(my_vars, left, temp, "0", ALPHA);
}

void if_command(line, ses)
     char *line;
     struct session *ses;
{
	char left[BUFFER_SIZE], right[BUFFER_SIZE], temp[BUFFER_SIZE];
	char elsebuf[BUFFER_SIZE];
	/* int i; */

	line = get_arg_in_braces(line, left, 0);
	line = get_arg_in_braces(line, right, 1);
	/* MOVED by if-else addition
	   substitute_vars(right,temp);
	   substitute_myvars(temp,right,ses);
	 */
	substitute_vars(left, temp);
	substitute_myvars(temp, left, ses);
	if (eval_expression(left)) {
		/* MOVED to here */
		substitute_vars(right, temp);
		substitute_myvars(temp, right, ses);
		parse_input(right, ses);
	}
	else {
		/* ADDITION for if-else addition */
		line = (char *) get_arg_stop_spaces(line, elsebuf);
		if (*elsebuf && strcmp(elsebuf, "else") == 0) {
			line = get_arg_in_braces(line, elsebuf, 1);
			substitute_vars(elsebuf, temp);
			substitute_myvars(temp, elsebuf, ses);
			parse_input(elsebuf, ses);
		}
	}
}


int eval_expression(arg)
     char *arg;
{
	int i, begin, end, flag, prev;
	char temp[BUFFER_SIZE];
	i = conv_to_ints(arg);

	if (i == 1) {		/* changed for if strings */
		while (1) {
			i = 0;
			flag = 1;
			begin = -1;
			end = -1;
			prev = -1;
			while (stacks[i][0] && flag) {
				if (stacks[i][1] == 0) {
					begin = i;
				}
				else if (stacks[i][1] == 1) {
					end = i;
					flag = 0;
				}
				prev = i;
				i = stacks[i][0];
			}
			if ((flag && (begin != -1)) || (!flag && (begin == -1))) {
				tintin_puts2("#Unmatched parentheses error.", (struct session *) NULL);
				return 0;
			}
			if (flag) {
				if (prev == -1)
					return (stacks[0][2]);
				begin = -1;
				end = i;
			}
			i = do_one_inside(begin, end);
			if (!i) {
				sprintf(temp, "#Invalid expression to evaluate in {%s}", arg);
				tintin_puts2(temp, (struct session *) NULL);
				return 0;
			}
		}
	}
	else if (i == 2)
		return 1;	/* changed for #if strings */
	else
		return 0;
}

int conv_to_ints(arg)
     char *arg;
{
	int i, flag;
	char *ptr, *tptr;
	char left[256], right[256];

	i = 0;
	ptr = arg;
	while (*ptr) {
		if (*ptr == ' ')
			;
		/* START ADDITION for #if-strings */
		else if (*ptr == '[') {
			ptr++;
			tptr = left;
			while ((*ptr) && (*ptr != ']') && (*ptr != '=')) {
				*tptr = (*ptr);
				ptr++;
				tptr++;
			}
			*tptr = '\0';
			if (!*ptr)
				return -1;
			if (*ptr == ']')
				return -2;
			tptr = right;
			ptr++;
			while ((*ptr) && (*ptr != ']')) {
				*tptr = (*ptr);
				ptr++;
				tptr++;
			}
			*tptr = '\0';
			if (!*ptr)
				return -1;
			if (strcmp(right, left) == 0)
				return 2;
			return 3;
		}
		/* END ADDITION for #if-strings */

		else if (*ptr == '(') {
			stacks[i][1] = 0;
		}
		else if (*ptr == ')') {
			stacks[i][1] = 1;
		}
		else if (*ptr == '!') {
			if (*(ptr + 1) == '=') {
				stacks[i][1] = 12;
				ptr++;
			}
			else
				stacks[i][1] = 2;
		}
		else if (*ptr == '*') {
			stacks[i][1] = 3;
		}
		else if (*ptr == '/') {
			stacks[i][1] = 4;
		}
		else if (*ptr == '+') {
			stacks[i][1] = 5;
		}
		else if (*ptr == '-') {
			flag = -1;
			if (i > 0)
				flag = stacks[i - 1][1];
			if (flag == 15)
				stacks[i][1] = 6;
			else {
				tptr = ptr;
				ptr++;
				while (isdigit(*ptr))
					ptr++;
				sscanf(tptr, "%d", &stacks[i][2]);
				stacks[i][1] = 15;
				ptr--;
			}
		}
		else if (*ptr == '>') {
			if (*(ptr + 1) == '=') {
				stacks[i][1] = 8;
				ptr++;
			}
			else
				stacks[i][1] = 7;
		}
		else if (*ptr == '<') {
			if (*(ptr + 1) == '=') {
				ptr++;
				stacks[i][1] = 10;
			}
			else
				stacks[i][1] = 9;
		}
		else if (*ptr == '=') {
			stacks[i][1] = 11;
			if (*(ptr + 1) == '=')
				ptr++;
		}
		else if (*ptr == '&') {
			stacks[i][1] = 13;
			if (*(ptr + 1) == '&')
				ptr++;
		}
		else if (*ptr == '|') {
			stacks[i][1] = 14;
			if (*(ptr + 1) == '|')
				ptr++;
		}
		else if (isdigit(*ptr)) {
			stacks[i][1] = 15;
			tptr = ptr;
			while (isdigit(*ptr))
				ptr++;
			sscanf(tptr, "%d", &stacks[i][2]);
			ptr--;
		}
		else if (*ptr == 'T') {
			stacks[i][1] = 15;
			stacks[i][2] = 1;
		}
		else if (*ptr == 'F') {
			stacks[i][1] = 15;
			stacks[i][2] = 0;
		}
		else {
			tintin_puts2("#Error. Invalid expression in #if or #math", (struct session *) NULL);
			return 0;
		}
		if (*ptr != ' ') {
			stacks[i][0] = i + 1;
			i++;
		}
		ptr++;
	}
	if (i > 0)
		stacks[i][0] = 0;
	return 1;
}

int do_one_inside(begin, end)
     int begin;
     int end;
{
	/* int prev, ptr, highest, loc, ploc, next, nval, flag; */
	int prev, ptr, highest, loc, ploc, next;
	while (1) {
		ptr = 0;
		if (begin > -1)
			ptr = stacks[begin][0];
		highest = 16;
		loc = -1;
		ploc = -1;
		prev = -1;
		while (ptr < end) {
			if (stacks[ptr][1] < highest) {
				highest = stacks[ptr][1];
				loc = ptr;
				ploc = prev;
			}
			prev = ptr;
			ptr = stacks[ptr][0];
		}
		if (highest == 15) {
			if (begin > -1) {
				stacks[begin][1] = 15;
				stacks[begin][2] = stacks[loc][2];
				stacks[begin][0] = stacks[end][0];
				return 1;
			}
			else {
				stacks[0][0] = stacks[end][0];
				stacks[0][1] = 15;
				stacks[0][2] = stacks[loc][2];
				return 1;
			}
		}
		else if (highest == 2) {
			next = stacks[loc][0];
			if (stacks[next][1] != 15 || stacks[next][0] == 0) {
				return 0;
			}
			stacks[loc][0] = stacks[next][0];
			stacks[loc][1] = 15;
			stacks[loc][2] = !stacks[next][2];
		}
		else {
			next = stacks[loc][0];
			if (ploc == -1 || stacks[next][0] == 0 || stacks[next][1] != 15)
				return 0;
			if (stacks[ploc][1] != 15)
				return 0;
			switch (highest) {
			case 3:	/* highest priority is * */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] *= stacks[next][2];
				break;
			case 4:	/* highest priority is / */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] /= stacks[next][2];
				break;
			case 5:	/* highest priority is + */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] += stacks[next][2];
				break;
			case 6:	/* highest priority is - */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] -= stacks[next][2];
				break;
			case 7:	/* highest priority is > */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] = (stacks[ploc][2] > stacks[next][2]);
				break;
			case 8:	/* highest priority is >= */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] = (stacks[ploc][2] >= stacks[next][2]);
				break;
			case 9:	/* highest priority is < */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] = (stacks[ploc][2] < stacks[next][2]);
				break;
			case 10:	/* highest priority is <= */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] = (stacks[ploc][2] <= stacks[next][2]);
				break;
			case 11:	/* highest priority is == */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] = (stacks[ploc][2] == stacks[next][2]);
				break;
			case 12:	/* highest priority is != */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] = (stacks[ploc][2] != stacks[next][2]);
				break;
			case 13:	/* highest priority is && */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] = (stacks[ploc][2] && stacks[next][2]);
				break;
			case 14:	/* highest priority is || */
				stacks[ploc][0] = stacks[next][0];
				stacks[ploc][2] = (stacks[ploc][2] || stacks[next][2]);
				break;
			default:
				tintin_puts2("#Programming error *slap Bill*", (struct session *) NULL);
				return 0;
			}
		}
	}
}