/* --------------------------- Ue19.c ------------------------------ */

#include "uedit.h"

static struct DB *toB;
static short	len,ind,slen,blanks;

#define MAX_F	 15

void initFolds()
{
register struct FOLD	*tt;

		nullify(foldTests[0].x,(long)sizeof(foldTests));
		tt = (struct FOLD *)foldTests[0].x;
		tt[0].f = 1; tt[0].num = 1; tt[0].x[0] = 0; tt[0].sk = 1;
		tt[1].f = 3; tt[1].num = 1; tt[1].x[0] = 0; tt[1].sk = 1;
		maxTest = 2;
}

FsetFold()
{
register struct FOLD	*tt;
register UCHAR  		*xx;
register short  		t,f,i,j;

	t = (short)*longPtrArgs[0];
	if (t==0) { 										/* clear all tests */
		initFolds();
		return(TRUE);
	}
	t--;
	if (t<0 || t>=MAX_T) return(FALSE);
	
	f = (short)*longPtrArgs[1];
	tt = (struct FOLD *)foldTests[0].x;
	if (f==0) { 										   /* clear test t */
		nullify(foldTests[t].x,(long)sizeof(struct FOLD));
		maxTest = 0;
		for (t=0; t<MAX_T; t++) if (tt[t].f) maxTest = t + 1;
		return(TRUE);
	}
	if (f<0 || f>MAX_F) return(FALSE);
	tt = (struct FOLD *)foldTests[t].x;
	i = (UCHAR)*longPtrArgs[3];
	if (f==15 && i==2) return(FALSE);
	tt->sk = i;
	i = args[2];
	if (i==buf_ || i==literal_) {
		if (f < 8) return(FALSE);
		xx = fixString(0,2,5);
		if (xx==NULL) return(FALSE);
		i = strlen(xx);
		if (i==0) return(FALSE);
		if (i>4) i = 4;
		if (f>=11) {	/* need 2 chars here */
			if (i==1) return(FALSE);
			if (f<14 && xx[1]<xx[0]) return(FALSE);
			i = 2;
		}
		movdat((UCHAR *)xx,(UCHAR *)tt->x,(short)i);
		tt->num = i;
	} else {
		if (f > 7) return(FALSE);
		if (f==1) j = 0;
		else {
			j = (short)*longPtrArgs[2];
			if (j < 0 || j > 130) return(FALSE);
		}
		tt->x[0] = (UCHAR)j;
		tt->num = 1;
	}
	tt->f = f;
	if (t>=maxTest) maxTest = t + 1;
	return(TRUE);
}

FgetFold()
{
register struct FOLD	*tt;
register UCHAR  		*x;
register short  		t,f,i,j;

	t = (short)*longPtrArgs[0];
	*longPtrArgs[1] = 0;
	if (t==0) { 
		*longPtrArgs[0] = maxTest;
		return(TRUE);
	}
	
	if (maxTest==0) return(FALSE);
	
	t--;
	if (t<0 || t>=MAX_T) return(FALSE);
	
	tt = (struct FOLD *)foldTests[t].x;
	f = tt->f;
	if (f==0) return(FALSE);
	*longPtrArgs[1] = f;
	*longPtrArgs[4] = tt->sk;
	
	*longPtrArgs[2] = tt->x[0];
	if (f>=8) {
		if (args[3]!=buf_) return(FALSE);
		j = (short)*longPtrArgs[3];
		if (j<0 || j>=ALLBUFS) return(FALSE);
		if (!fixBuf(j)) return(FALSE);
		x = buf[j]->NextBlock->Data;
		for (i=0; i<tt->num; i++) *(x++) = tt->x[i];
		*x = EOFILE;
	}
	return(TRUE);
}

static long lines;
static short didline,linecol;

Ffold()
{
register short  	i;
register long		saveColumnar,ggp,ffp,ffb;
register struct CB  *bufPtr,*toBufPtr;

	if (maxTest==0) return(FALSE);
	bufPtr = bufPtrArgs[1];
	if (bufPtr==NULL) return(FALSE);
	getBP(bufPtr,2);
	ffb = (long)fB;
	if (ffb==NULL || gB==NULL) return(FALSE);
	
	ggp = (long)gP;
	ffp = (long)fP;
	/* put start/end of rgn onto line boundaries */
	fastBufPtr = bufPtr; fastB = (struct DB *)ffb; fastP = (UCHAR *)ffp;
	solFast();
	ffp = (long)fastP; ffb = (long)fastB;
	fastP = (UCHAR *)ggp; fastB = gB;
	if (*fastP!=EOFILE) solFast();
	ggp = (long)fastP; gB = fastB;
	if (loc(gB,(UCHAR *)ggp) <= loc((struct DB *)ffb,(UCHAR *)ffp)) return(FALSE);

	if (args[0]==literal_) {
		if (!FnewFile()) { popFast(); return(FALSE); }
		toBufPtr = curBuf;
	} else {
		i = (short) *longPtrArgs[0];
		if (!getBuf(i) || !canChange(toBufPtr = buf[i])) return(FALSE);
		fastBufPtr = toBufPtr;
		fastB = toBufPtr->NextBlock;
		fastP = fastB->Data;
		eFileFast();
		toBufPtr->Block = fastB;
		toBufPtr->Ptr = fastP;
	}
	curTable = tabTables[bufPtr->tabTable];
	toBufPtr->tabTable = bufPtr->tabTable;

	oneMsg("folding...");
	saveColumnar = columnar;
	columnar = 0;
	pushFast(bufPtr,&(bufPtr->Block),&(bufPtr->Ptr));
	fastP = (UCHAR *)ffp;
	fastB = (struct DB *)ffb;
	didline=0;
    lines = 0L;
    linecol = (short)*longPtrArgs[3];
/*    if (lc) fastBufPtr->PageLines = 1; */
	blanks = 0;
	saveBufPtr = toBufPtr;
	toBufPtr = (struct CB *)z;
	while (1) {
		if (fastP==(UCHAR *)ggp) break;
		lineInfo();
		if (*((UCHAR *)toBufPtr)==0x00) break;
		if (lineTest()) copyLine();
        if (msgList->lh_Head->ln_Succ) {
            if (stop()) break;
        }
    }
	toBufPtr = saveBufPtr;
	if (didline) toBufPtr->Flags |= (CHANGED | NEEDPACK);
	columnar = saveColumnar;
	splitFlag(toBufPtr->BufNum,PAGE_ | SHOWCURSOR_);
	clearMsg();
	popFast();
	if (didline==0L) return(FALSE);
	return(TRUE);
}

void lineInfo()
{
register UCHAR  	*fP,*p;
register UCHAR  	ch,eoline,j,length,indent;
register short  	spaces;

	eoline = eol;
	p = z;
	spaces = TRUE;
	indent = length = 1;
	fP = fastP;
	while (1) {
		ch = *fP;
		fP = incFast();
		if (ch==TAB) {
			curCol = length;
			j = (UCHAR)tabCalc();
			length += j;
			if (j) goto CONT1;
			length++;
			goto CONT1;
		}
		if (ch!=' ') spaces=FALSE;
		length++;
		if (ch==EOFILE) {
			if (length==2) { *z = 0x00; return; }
			*(p++) = eol;
			break;
		}
CONT1:
		*(p++) = ch;
		if (spaces) indent = length;
		if (length>=(MAXLINECHARS-1))
			{ decFast(); decFast(); eLineFast(); incFast(); *(p-1)=eol; break; }
		if (ch<14) {
			if (ch==eoline || ch==12) break;
		}
	}
	indent--;
	length -= 2;
	ind = indent; len = length;
	*p = 0x00;
	slen = (short)(p - z - 2);
    lines++;
}

void copyLine()
{
register UCHAR  	*toP,*p,ch;
register short      i,j;
register ULONG  	bufPtr;
	
	if (ind!=len) blanks = 0;
	p = (UCHAR *)saveBufPtr;
	toP = ((struct CB *)p)->Ptr;	  /* always at EOFILE */
	toB = ((struct CB *)p)->Block;
	bufPtr = (ULONG)p;
    j = linecol;
    if (j) {
        p = passive;
        stci_d(p,lines);  /* FIX: stci_d() should return LEN */
        i = strlen(p);
        p += i;
        while (i<8) {
            *(p++) = ' ';
            i++;
        }
        *p = 0x00;
        p = passive;
    } else p = z;
	while (1) {
		ch = *(p++);
        if (j) {
            if (ch==0x00) {
                p = z;
                ch = *(p++);
                j = 0;
            }
        }
		if (*toP==EOB) {
			if (newBlock((struct CB *)bufPtr,&toB,toB)) toP = toB->Data;
			else { toP--; goto DONE; }
		}
		if (ch==0) break;
		*(toP++) = ch;
	}
	if (*toP==EOB) {
		if (newBlock((struct CB *)bufPtr,&toB,toB)) toP = toB->Data;
		else toP--;
	}
DONE:
	*toP = EOFILE;
	p = (UCHAR *)bufPtr;
	((struct CB *)p)->Ptr = toP; ((struct CB *)p)->Block = toB;
    didline=1;
}

static short i,rtn;
static struct  FOLD *t;

lineTest()
{
register UCHAR  		*x,*y;
register short  		ANDing;
register UCHAR  		f,c0,c1,c2,c3;

	i = 0;
	ANDing = 0;
	while (1) {
TOP:
		rtn = 0;
TOP2:
		if (i>=maxTest) return(FALSE);
		y = foldTests[i].x;
		i++;
		f = ((struct FOLD *)y)->f;
		if (f==0) goto TOP;
		if (ANDing && rtn==0) {
			if (((struct FOLD *)y)->sk==2) goto TOP2;
			ANDing = 0;
			goto TOP2;
		}
		ANDing = 0;
		if (((struct FOLD *)y)->sk==2) ANDing = 1;
		t = (struct FOLD *)y;
		c0 = *(y++);
		if (f<8) switch (f) {
		case 1: 	if (ind==len) {
						if (blanks) return(0);
						blanks = 1;
						goto RSK;  /* blank line */
					}
					goto TOP;
		case 2: 	if ((UCHAR)ind==c0) goto RSK;
					goto TOP;
		case 3: 	if ((UCHAR)ind==0 || (UCHAR)ind < c0) goto RSK;
					goto TOP;
		case 4: 	if ((UCHAR)ind > c0) goto RSK;
					goto TOP;
		case 5: 	if ((UCHAR)len==c0) goto RSK;
					goto TOP;
		case 6: 	if ((UCHAR)len==0 || (UCHAR)len < c0) goto RSK;
					goto TOP;
		case 7: 	if ((UCHAR)len > c0) goto RSK;
					goto TOP;
		} else {
			c1 = *(y++);
			x = z;
			switch (f) {
			case 8: /* 1-4 string X (eg, "x" or "abcd") in line */
					c2 = *(y++);
					c3 = *(y++);
					while (1) {
						f = *x;
						if (f==0) goto TOP;
						if (f==c0) {
							if (c1==0) goto RSK;
							if (x[1]==c1) {
								if (c2==0) goto RSK;
								if (x[2]==c2) {
									if (c3==0) goto RSK;
									if (x[3]==c3) goto RSK;
								}
							}
						}
						x++;
					}
					goto TOP;
			case 9: /* 1-4 string X at sol */
					if (c0 == *(x++)) {
						if (c1==0) goto RSK;
						if (c1 == *(x++)) {
							c2 = *(y++);
							if (c2==0) goto RSK;
							if (c2 == *(x++)) {
								c3 = *(y++);
								if (c3==0) goto RSK;
								if (c3 == *x) goto RSK;
							}
						}
					}
					goto TOP;
			case 10: /* 1-4 string X at eol */
					f = slen - t->num + 1;
					if (f<0) goto TOP;
					x += f;
					if (*(x++)!=c0) goto TOP;
					if (c1==0) goto RSK;
					if (*(x++)!=c1) goto TOP;
					c2 = *(y++);
					if (c2==0) goto RSK;
					if (*(x++)!=c2) goto TOP;
					c3 = *(y++);
					if (c3==0) goto RSK;
					if (*x==c3) goto RSK;
					goto TOP;
			case 11: /* char in range X (eg, "AZ" or "09") in line */
					while (1) {
						f = *(x++);
						if (f==0) goto TOP;
						if (f>=c0 && f<=c1) goto RSK;
					}
					goto TOP;
			case 12: /* char in range X (eg, "AZ" or "09") at sol */
					c2 = *x;
					if (c2>=c0 && c2<=c1) goto RSK;
					goto TOP;
			case 13: /* char in range X (eg, "AZ" or "09") at eol */ 
					f = slen;
					c2 = x[f];
					if (f>=0 && c2>=c0 && c2<=c1) goto RSK;
					goto TOP;
			case 14: /* rgn of quotes or brackets in X in line */
					while (1) {
						c2 = *(x++);
						if (c2==0) goto TOP;
						if (c2==c0) break;
					}
					while (1) {
						c2 = *(x++);
						if (c2==0) goto TOP;
						if (c2==c1) goto RSK;
					}
					goto TOP;
			case 15: /* bracketed rgn in multi-lines */
					f = 0;
					y = (UCHAR *)t;
					if (((struct FOLD *)y)->sk==2) goto TOP;
					while (1) {
						c2 = *(x++);
						if (c2==0) goto TOP;
						if (c2==c0) { f++; break; }
					}
					if (c0==c1) c0 = 0;
AGAIN:
					while (1) {
						c2 = *(x++);
						if (c2==0) break;
						if (c2==c0) f++;
						if (c2==c1) {
							f--;
							if (f==0) goto RSK;
						}
					}
					if (((struct FOLD *)y)->sk) copyLine();
					if (fastP==gP) return(0);
					lineInfo();
					x = z;
					if (*x==0x00) return(0);
					goto AGAIN;
			}
		}
	}
	return(FALSE);
RSK:
	f = t->sk;
	if (f==2) { rtn = TRUE; goto TOP2; }
	return(f);
}

