/*	@(#)sno3.c	1.1	*/
#include "sno.h"

/*
 * sno3
 */


int
bextend (str, last)
	struct node *str, *last;
{
	register struct node *a, *s;
	register int b;
	struct node *cc;
	int c, d;

	s = str;
	if ((cc = s->p1) == 0)
		goto bad;
	b = d = 0;
	a = s->p2;
	if (a == 0) {
		a = cc;
		goto eb2;
	}
eb1:
	if (a == last)
		goto bad;
	a = a->p1;
eb2:
	d++;
	c = class (a->ch);
	if (c == 1) { /* rp */
		if (b == 0)
			goto bad;
		b--;
		goto eb3;
	}
	if (c == 2) { /* lp */
		b++;
		goto eb1;
	}
eb3:
	if (b == 0) {
		s->p2= a;
		return (d);
	}
	goto eb1;
bad:
	return (0);
}

int
ubextend (str, last)
	struct node *str, *last;
{
	register struct node *a, *b, *s;

	s = str;
	a = s->p1;
	if (a == 0)
		goto bad;
	b = s->p2;
	if (b == 0)
		goto good;
	if (b == last)
		goto bad;
	a = b->p1;
good:
	s->p2 = a;
	return (1);
bad:
	return (0);
}

struct node *
search (arg, r)
	struct node *arg, *r;
{
	struct node *list, *back, *str,
		*etc, *next, *last, *base, *e;
	register struct node *a, *b, *var;
	int c, d;

	a = arg->p2;
	list = base = salloc();
	last = next = 0;
	goto badv1;
badvanc:
	a = a->p1;
	if (a->typ == 0) {
		list->p1 = 0;
		if (rfail == 1) {
			a = 0;
			goto fail;
		}
		list = base;
		if (r == 0)
			next = last = 0;
		else {
			next = r->p1;
			last = r->p2;
		}
		goto adv1;
	}
	b = salloc();
	list->p1 = b;
	list = b;
badv1:
	list->p2 = back = salloc();
	back->p1 = last;
	b = a->p2;
	c = a->typ;
	list->typ = c;
	if (c < 2) {
		back->p2 = eval (b, 1);
		goto badvanc;
	}
	last = list;
	str = salloc();
	etc = salloc();
	back->p2 = var = salloc();
	var->typ = b->typ;
	var->p1 = str;
	var->p2 = etc;
	e = b->p1;
	if (e == 0)
		etc->p1 = 0;
	else
		etc->p1 = eval (e, 0);
	e = b->p2;
	if (e == 0)
		etc->p2 = 0;
	else {
		e = eval (e, 1);
		etc->p2 = (struct node *) strbin (e);
		delete (e);
	}
	goto badvanc;

retard:
	a = back->p1;
	if (a == 0) {
		rfail = 1;
		goto fail;
	}
	list = a;
	back = list->p2;
	var = back->p2;
	str = var->p1;
	etc = var->p2;
	if (etc->p2)
		goto retard;
	if (var->typ == 1) {
		if (bextend (str, last) == 0)
			goto retard;
		goto adv0;
	}
	if (ubextend (str, last) == 0)
		goto retard;
adv0:
	a = str->p2;
adv01:
	if (a == last)
		next = 0;
	else
		next = a->p1;
advanc:
	a = list->p1;
	if (a == 0) {
		a = salloc();
		if (r == 0) {
			a->p1 = a->p2 = 0;
			goto fail;
		}
		b = r->p1;
		a->p1 = b;
		if (next == 0) {
			a->p2 = r->p2;
			goto fail;
		}
		while (1) {
			e = b->p1;
			if (e == next) {
				a->p2 = b;
				goto fail;
			}
			b = e;
		}
	}
	list = a;
adv1:
	back = list->p2;
	var = back->p2;
	d = list->typ;
	if (d < 2) {
		if (var == 0)
			goto advanc;
		if (next == 0)
			goto retard;
		a = next;
		b = var->p1;
		e = var->p2;
		while (1) {
			if (a->ch != b->ch)
				goto retard;
			if (b == e)
				goto adv01;
			if (a == last)
				goto retard;
			a = a->p1;
			b = b->p1;
		}
	}
	str = var->p1;
	etc = var->p2;
	str->p1 = next;
	str->p2 = 0;
	c = (int) etc->p2;
	if (var->typ == 1) {
		d = bextend (str, last);
		if (d == 0)
			goto retard;
		if (c == 0)
			goto adv0;
		while (1) {
			c -= d;
			if (c == 0)
				goto adv0;
			if (c < 0)
				goto retard;
			d = bextend (str, last);
			if (d == 0)
				goto retard;
		}
	}
	if (c == 0) {
		if (d==3 && next!=0) {
			str->p2 = last;
			goto adv0;
		}
		goto advanc;
	}
	while (c--)
		if (ubextend (str, last) == 0)
			goto retard;
	goto adv0;

fail:
	list = base;
	goto f1;
fadv:
	sfree (back);
	b = list->p1;
	sfree (list);
	if (b == 0)
		return (a);
	list = b;
f1:
	back = list->p2;
	var = back->p2;
	if (list->typ < 2) {
		delete (var);
		goto fadv;
	}
	str = var->p1;
	etc = var->p2;
	if (a != 0 && etc->p1 != 0) {
		if (str->p2 == 0) {
			sfree (str);
			str = 0;
		}
		assign (etc->p1, copy (str));
	}
	if (str)
		sfree (str);
	sfree (etc);
	sfree (var);
	goto fadv;
}
