#include    <jctype.h>

#define	TRUE	1
#define	FALSE	0
#define	ERR	(-1)

#define BUF_MAX 512
#define BUF_MSK 511
#define LIN_MAX 128

char	*file_ext();

extern	int	fext_top;
extern	int	fext_pos;

static  int     his_pos=0;
static  int     his_top=0;
static  int     his_old=0;
static  int     his_blk=0;
static  char    *his_lin;
static  char    his_buf[BUF_MAX];
static  int     his_len[2]={0,0};
static  char    his_tmp[2][LIN_MAX];

/************************
int	iskanji(ch)
unsigned char ch;
{
    return ( (ch >= 0x81 && ch <= 0x9F) ||
	     (ch >= 0xE0 && ch <= 0xFC) ? TRUE:FALSE);
}
int	iskanji2(ch)
unsigned char ch;
{
    return ( (ch >= 0x40 && ch <= 0x7E) ||
	     (ch >= 0x80 && ch <= 0xFC) ? TRUE:FALSE);
}
**************************/
int     iskan(p)
char    *p;
{
    if ( iskanji(*p) && iskanji2(*(p+1)) )
        return TRUE;
    else
        return FALSE;
}
int     kan_pos(p,len)
register char *p;
int     len;
{
    int     i,n;

    for ( i = 0 ; *p != '\0' && i < len ; ) {
        n = (iskan(p) ? 2:1);
        if ( (i + n) > len )
            break;
        i += n;
        p += n;
    }
    return i;
}
static  void    his_set(str,len)
char    *str;
int     len;
{
    int     c;

    while ( len-- > 0 && *str != '\0' ) {
        his_buf[his_pos++] = *(str++);
        his_pos &= BUF_MSK;
        if ( his_pos == his_top ) {
            do {
                c = his_buf[his_top++];
                his_top &= BUF_MSK;
            } while ( his_top != his_pos && c != '\n' );
        }
    }
}
static  int     his_next(pos)
int     pos;
{
    int     c;

    while ( pos != his_pos ) {
        c = his_buf[pos++];
        pos &= BUF_MSK;
        if ( c == '\n' )
            break;
    }
    return pos;
}
static  int     his_back(pos)
int     pos;
{
    int     c;

    if ( pos == his_top )
        return pos;

    pos = (pos - 1) & BUF_MSK;
    while ( pos != his_top ) {
        pos = (pos - 1) & BUF_MSK;
        if ( his_buf[pos] == '\n' ) {
            pos = (pos + 1) & BUF_MSK;
            break;
        }
    }
    return pos;
}
static  int     his_get(str,pos,off,max)
char    *str;
int     pos;
int     off;
int     max;
{
    int     i,n;

    i = 0;
    while ( i < max && pos != his_pos ) {
        if ( his_buf[pos] == '\n' )
            break;
        else if ( iskanji(his_buf[pos]) &&
                  iskanji2(his_buf[(pos+1)&BUF_MSK]) )
            n = 2;
        else
            n = 1;

        if ( (i + n) > max )
            break;

        if ( i >= off ) {
            i += n;
            while ( n-- > 0 ) {
                *(str++) = his_buf[pos++];
                pos &= BUF_MSK;
            }
        } else {
            pos = (pos + n) & BUF_MSK;
            while ( n-- > 0 ) {
                if ( ++i > off )
                    *(str++) = ' ';
                else
                    str++;
            }
        }
    }
    return (i > off ? i:off);
}
static  int     his_cmp(pos,str,len)
int     pos;
char    *str;
int     len;
{
    while ( len > 0 && *str != '\0' ) {
        if ( pos == his_pos || his_buf[pos++] != *(str++) )
            return FALSE;
        pos &= BUF_MSK;
        len--;
    }
    return TRUE;
}
char    *input(max)
int	max;
{
    int     ch,och,n,i;
    int     pos,cps,len,his;
    char    *p,*s;

    ch = pos = cps = len = 0;
    his = his_pos;
    his_lin = his_tmp[his_blk];

    if ( max > LIN_MAX )
	max = LIN_MAX;

    if ( --max < 0 ) {
	his_lin[0] = '\n';
	len = 1;
	goto ENDOF;
    }

    for ( ; ; ) {

	och = ch;

        if ( (ch = GETCH()) == 0x1B )
	    ch = (ch << 8) | GETCH();

        switch(ch) {
        case 0x08:
            if ( pos > 0 ) {
                pos = kan_pos(his_lin,pos - 1);
                p = &(his_lin[pos]);
                n = (iskan(p) ? 2:1);
                memcpy(p,p + n,len - pos - n);
                len -= n;

                BAKSPC(n);
                PUTS(p,len - pos);
                REPCHR(' ',n);
                BAKSPC(len - pos + n);
            }
            break;

        case 0x1B56:
            if ( pos < len ) {
                p = &(his_lin[pos]);
                n = (iskan(p) ? 2:1);
                memcpy(p,p + n,len - pos - n);
                len -= n;

                PUTS(p,len - pos);
                REPCHR(' ',n);
                BAKSPC(len - pos + n);
            }
            break;

        case 0x1C:
            if ( pos < len ) {
                p = &(his_lin[pos]);
                n = (iskan(p) ? 2:1);
                pos += n;

                while ( n-- > 0 )
                    PUTC(*(p++));
            }
            break;

        case 0x1D:
            if ( pos > 0 ) {
                pos = kan_pos(his_lin,pos - 1);
                p = &(his_lin[pos]);
                n = (iskan(p) ? 2:1);

                BAKSPC(n);
            }
            break;

	case 0x1E:
	    for ( ; ; ) {
        	if ( his == his_top ) {
		    BEEP();
		    break;
		}

                his = his_back(his);
		cps = ((och == 0x1F || och == 0x1E) ? cps:pos);
                if ( !his_cmp(his,his_lin,cps) )
                    continue;

                BAKSPC(pos);
                REPCHR(' ',len);
                BAKSPC(len);

                pos = len = his_get(his_lin,his,0,max);

                PUTS(his_lin,len);
                BAKSPC(len - pos);
                break;
            }
            break;

        case 0x1F:
            for ( ; ; ) {
		if ( his == his_pos ) {
		    BEEP();
		    REPCHR(' ',len - pos);
		    BAKSPC(len - pos);
		    len = pos;
		    break;
		}

                his = his_next(his);
		cps = ((och == 0x1F || och == 0x1E) ? cps:pos);
                if ( !his_cmp(his,his_lin,cps) )
                    continue;

                BAKSPC(pos);
                REPCHR(' ',len);
                BAKSPC(len);

                pos = len = his_get(his_lin,his,0,max);

                PUTS(his_lin,len);
                BAKSPC(len - pos);
                break;
            }
            break;

	case 0x16:
        case 'R'-'@':
            if ( his != his_top ) {
                his = his_back(his);

                REPCHR(' ',len - pos);
                BAKSPC(len - pos);

                len = his_get(his_lin,his,pos,max);

                PUTS(&(his_lin[pos]),len - pos);
                BAKSPC(len - pos);
            } else
		BEEP();
            break;

	case 0x17:
        case 'E'-'@':
            if ( his != his_pos ) {
                his = his_next(his);

                REPCHR(' ',len - pos);
                BAKSPC(len - pos);

                len = his_get(his_lin,his,pos,max);

                PUTS(&(his_lin[pos]),len - pos);
                BAKSPC(len - pos);
            } else
		BEEP();
            break;

	case 0x1B55:
        case 'A'-'@':
            p = &(his_lin[len]);
            while ( len < max && *p != '\n' && *p != '\0' ) {
                len++;
                p++;
            }
            PUTS(&(his_lin[pos]),len - pos);
            pos = len;
            break;

        case 0x0D:
            his_lin[len++] = '\n';
            if ( len > 1 && !his_cmp(his_old,his_lin,len) ) {
		his_old = his_pos;
                his_set(his_lin,len);
	    }

            PUTS(&(his_lin[pos]),len - pos);
            goto ENDOF;

        case 'X'-'@':
            BAKSPC(pos);
            REPCHR(' ',len);
            BAKSPC(len);
            pos = len = 0;
            break;

	case 0x0B:
        case 'D'-'@':
            BAKSPC(pos);
            REPCHR(' ',len);
            BAKSPC(len);

            his_len[his_blk] = len;
            his_blk ^= 1;
            his_lin = his_tmp[his_blk];
            pos = len = his_len[his_blk];

            PUTS(his_lin,len);
            break;

        case 'U'-'@':
	    if ( och != ('U'-'@') )
		file_end();

	    s = file_ext(his_lin,pos);

	    if ( (n = fext_pos + strlen(s) - pos) > 0 ) {
		if ( pos < len ) {
                    p = &(his_lin[len + (n - 1)]);
                    for ( i = len - pos ; i > 0 ; i--,p-- )
                        *p = *(p - n);
                }
	    } else if ( n < 0 ) {
		if ( pos < len )
		    memcpy(&(his_lin[pos+n]),&(his_lin[pos]),len-pos);
	    }

	    p = &(his_lin[fext_pos]);
	    while ( *s != '\0' )
		*(p++) = *(s++);

            BAKSPC(pos - fext_pos);
            REPCHR(' ',len - fext_pos);
            BAKSPC(len - fext_pos);

	    len += n;
	    pos += n;

            PUTS(&(his_lin[fext_pos]),len - fext_pos);
            BAKSPC(len - pos);
	    break;

        default:
            if ( iskanji(ch) ) {
                n = GETCH();
                if ( !iskanji2(n) ) {
                    UNGETCH(n);
                    n = 1;
                } else {
                    ch = (ch << 8) | n;
                    n = 2;
                }
            } else
                n = 1;

            if ( (len + n ) >= max ) {
                BEEP();
                break;
            }

            if ( pos < len ) {
                p = &(his_lin[len + (n - 1)]);
                for ( i = len - pos ; i > 0 ; i--,p-- )
                    *p = *(p - n);
            }

            p = &(his_lin[pos]);
            if ( n == 1 ) {
                his_lin[pos++] = ch;
            } else {
                his_lin[pos++] = ch >> 8;
                his_lin[pos++] = ch;
            }
            len += n;

            PUTS(p,len - pos + n);
            BAKSPC(len - pos);
            break;
        }
        FLUSH();
    }

ENDOF:
    his_len[his_blk] = len;
    return his_lin;
}
