/********************************************

	Screen Display Func

*********************************************/
#include    "defs.h"
#include    "scrn.h"

#ifdef	MSDOS
static	char far *FAR_STRCPY(char far *buf, register char *s)
{
    register char far *p = buf;

    while ( *s != '\0' )
	*(p++) = *(s++);
    *p = '\0';

    return buf;
}
static	char *NEAR_STRCPY(char *buf, register char far *s)
{
    register char *p = buf;

    while ( *s != '\0' )
	*(p++) = *(s++);
    *p = '\0';

    return buf;
}
#endif	/* MSDOS */

typedef	struct _LINPTR {
	struct _LINPTR	FAR	*next;
	struct _LINPTR	FAR	*back;
	int		line;
	char		str[1];
} LINPTR;

static	LINPTR	FAR	*dic_line_now = NULL;
static	int	dic_line_count = 0;
static	int	dic_mem_flag = FALSE;
static	char	dic_str_tmp[COLS_MAX + 2];

static	LINPTR	FAR	*dic_alloc_line(char *str, int line)
{
    LINPTR FAR *lp;

    if ( (lp = (LINPTR FAR *)MALLOC(sizeof(LINPTR) + strlen(str))) == NULL )
	return NULL;
    lp->next = lp->back = NULL;
    lp->line = line;
    FAR_STRCPY(lp->str, str);
    return lp;
}
static	void	dic_free_line()
{
    LINPTR FAR *lp;

    if ( dic_line_now != NULL ) {
    	while ( (lp = dic_line_now->back) != NULL )
	    dic_line_now = lp;
    }

    while ( (lp = dic_line_now) != NULL ) {
	dic_line_now = lp->next;
	FREE(lp);
    }
}
static	char	*dic_next_line()
{
    LINPTR FAR *lp;

    if ( cd_gets(dic_str_tmp, cols_max - 1, dic_line_count) == NULL ) {
	while ( menu_top != NULL ) {
	    menu_max--;
	    menu_top = menu_top->next;
	}
	while ( betu_top != NULL ) {
	    betu_max--;
	    betu_top = betu_top->next;
	}
	return NULL;
    }

    if ( dic_mem_flag )
	return dic_str_tmp;

    if ( (lp = dic_alloc_line(dic_str_tmp, dic_line_count)) == NULL ) {
	dic_mem_flag = TRUE;
	dic_free_line();
	return dic_str_tmp;
    }

    dic_line_count++;
    if ( dic_line_now != NULL ) {
	dic_line_now->next = lp;
	lp->back = dic_line_now;
    }
    dic_line_now = lp;

    return NEAR_STRCPY(dic_str_tmp, lp->str);
}
static	char	*dic_goto_line(int line)
{
    if ( dic_line_now == NULL )
	return NULL;

    while ( line < dic_line_now->line ) {
	if ( dic_line_now->back == NULL )
	    return NULL;
	dic_line_now = dic_line_now->back;
    }

    while ( line > dic_line_now->line ) {
	if ( dic_line_now->next == NULL )
	    return NULL;
	dic_line_now = dic_line_now->next;
    }

    return NEAR_STRCPY(dic_str_tmp, dic_line_now->str);
}
static	LINPTR	FAR	*dic_set_line(char *str)
{
    LINPTR FAR *lp;

    if ( (lp = dic_alloc_line(str, dic_line_count)) == NULL )
	return NULL;

    dic_line_count++;
    if ( dic_line_now != NULL ) {
	dic_line_now->next = lp;
	lp->back = dic_line_now;
    }
    dic_line_now = lp;

    return lp;
}
static	void	dic_set_menu(int line, int sx, int bx)
{
    if ( menu_max >= MENU_MAX )
	return;
    menu_tab[menu_max].sx = sx;
    menu_tab[menu_max].bx = bx;
    menu_tab[menu_max].sy = menu_tab[menu_max].by = line;
    menu_max++;
}
static	void	dic_init_line(int sw)
{
    dic_free_line();
    dic_line_count = 0;
    dic_mem_flag = sw ? FALSE:TRUE;
}

static	struct {
	short	flag;
	int	line;
	} scrn_tab[LINE_MAX];

static	void	dic_scrn_clear()
{
    int     n;

    for ( n = 0 ; n < lines_max ; n++ ) {
	scrn_tab[n].flag = (-3);
	scrn_tab[n].line = (-1);
    }
}
static	int	dic_menu_screen(int top, int menu)
{
    int     n;
    int     line;
    int     ps, st, ed;
    int     ex, flag;
    uchar   *p;

    while ( top > menu_tab[menu].sy )
	top--;

    while ( (menu_tab[menu].by - top) >= (lines_max - 1) )
	top++;

    line = top;
    st = menu_tab[menu].sy * COLS_MAX + menu_tab[menu].sx;
    ed = menu_tab[menu].by * COLS_MAX + menu_tab[menu].bx;

    CUROFF();
    for ( n = 0 ; n < (lines_max - 1) ; n++, line++ ) {

	flag = (line >= menu_tab[menu].sy &&
		line <= menu_tab[menu].by ? menu : (-1));

	if ( scrn_tab[n].flag == flag && scrn_tab[n].line == line )
	    continue;

	scrn_tab[n].line = line;
	scrn_tab[n].flag = flag;

	LOCATE(0, n);

	if ( (p = dic_goto_line(line)) == NULL ) {
	    ERALINE();
	    continue;
	}

	ex = FALSE;
	ps = line * COLS_MAX;
	while ( *p != '\n' && *p != '\0' ) {
	    if ( ex == FALSE && ps >= st && ps < ed ) {
		REVCOL();
		ex = TRUE;
	    }
	    if ( ex != FALSE && ps >= ed ) {
		STDCOL();
		ex = FALSE;
	    }
	    if ( *p >= ' ' )
	        PUTC(*p);
	    p++;
	    ps++;
	}
	if ( ex != FALSE )
	    STDCOL();
	if ( *p == '\n' )
	    ERALINE();
    }

    LOCATE(0, n);
    ERALINE();
    CURON();
    FLUSH();

    return top;
}
static	int	dic_menu_select(int top, int menu)
{
    int     ch;

#ifdef	CURSES
#ifdef	NEWS
    setlocale(LC_CTYPE, "");
#endif
    initscr();
    cbreak();
    noecho();
    scrollok(stdscr, TRUE);
    idlok(stdscr, TRUE);
    cols_max = COLS;
    lines_max = LINES;
#endif	/* CURSES */

    dic_scrn_clear();
    for ( ; ; ) {
	top = dic_menu_screen(top, menu);
	ch = GETCH();

	switch(ch) {
	case '\n': case '\r':
	    goto ENDOF;

	case '\033':
	case 'q': case 'Q': case 'Q'-'@':
	    menu = ERR;
	    goto ENDOF;

	case ' ':
	case '\x1F': case '\x1C':
	case 'd': case 'D': case 'D'-'@':
	case 'n': case 'N': case 'N'-'@':
	case 'j': case 'J': /* case 'J'-'@': */
	    if ( ++menu >= menu_max )
		menu = 0;
	    break;

	case '\b':
	case '\x1E': case '\x1D':
	case 'u': case 'U': case 'U'-'@':
	case 'p': case 'P': case 'P'-'@':
	case 'k': case 'K': case 'K'-'@':
	    if ( --menu < 0 )
		menu = menu_max - 1;
	    break;

	case 'L'-'@':
	    REFRESH();
	    break;
	}
    }

ENDOF:

    CLS();
    FLUSH();

#ifdef	CURSES
    endwin();
#endif

    return menu;
}
static	void	dic_puts(uchar *str, FILE *fp)
{
    for ( ; *str != '\0' ; str++ ) {
	if ( fp != NULL ) {
	    if ( tex_out_flag ) {
	        switch(*str) {
	        case CH_BOLD_ON:
		    fputs("\\bold{", fp);
		    break;
	        case CH_BOLD_OFF:
		    putc('}', fp);
		    break;
	        case CH_ITALIC_ON:
		    fputs("\\slide{", fp);
		    break;
	        case CH_ITALIC_OFF:
		    putc('}', fp);
		    break;
	        default:
		    putc(*str, fp);
		    break;
		}
	    } else {
	        if ( *str >= '\n' )
		    putc(*str, fp);
	    }
	} else if ( color_flag ) {
	    switch(*str) {
	    case CH_BOLD_ON:    BOLD_ON(); break;
	    case CH_BOLD_OFF:   BOLD_OFF(); break;
	    case CH_ITALIC_ON:  ITALIC_ON(); break;
	    case CH_ITALIC_OFF: ITALIC_OFF(); break;
	    case '\n': ERALINE(); PUTC('\n'); break;
	    default: PUTC(*str); break;
	    }
	} else {
	    if ( *str > '\n' )
	  	PUTC(*str);
	    else if ( *str == '\n' ) {
		ERALINE();
		PUTC('\n');
	    }
	}
    }
}
int	dic_display(ulong block, ushort offset)
{
    int     ch;
    int     line, max;
    int     menu = 0;
    int     fg = FALSE;
    char    *p;
    POINT   tab[1];
#ifdef	MORE
    FILE    *fp;
#endif	/* MORE */

LOOP:
    if ( dic_seek(block, offset) )
	return ERR;

    dic_init_line(menu_disp_flg);

    if ( menu_disp_flg == FALSE )
	goto NOMENU;

    for ( max = 0 ; max < MENU_CHK_LINE &&
		(p = dic_next_line()) != NULL ; max++ )
	;

    if ( dic_mem_flag ) {
	fprintf(stderr, "Menu Memory Alloc Error\n");
	return ERR;
    }

    if ( menu_max > 0 ) {
	while ( max < HONBUN_MAX_LINE && (p = dic_next_line()) != NULL )
	    max++;
	if ( dic_mem_flag ) {
	    fprintf(stderr, "Menu Memory Alloc Error\n");
	    return ERR;
	}
	line = max - lines_max + 1;
    	if ( (menu = dic_menu_select(0, menu)) < 0 )
	    return ERR;
	dic_display(menu_tab[menu].pos.block,
		    menu_tab[menu].pos.offset);
        goto LOOP;
    }

    fg = TRUE;

NOMENU:
    if ( extdisp_flag ) {
	tab[0].block = block;
	tab[0].offset = offset;
	pager(tab, 1, menu_disp_flg);
	return FALSE;
    }

#ifdef	MORE
    if ( pause_flg == FALSE || (fp = popen(MORE, "w")) == NULL )
	fp = stdout;
#endif	/* MORE */

    for ( max = line = 0 ; max < HONBUN_MAX_LINE ; max++ ) {

	if ( fg == TRUE && (p = dic_goto_line(max)) == NULL ) {
	    dic_mem_flag = TRUE;
	    dic_free_line();
	    fg = FALSE;
	}

	if ( fg == FALSE && (p = dic_next_line()) == NULL )
	    break;

	if ( ext_out_fp != NULL )
	    dic_puts(p, ext_out_fp);

#ifdef	MORE
	dic_puts(p, fp);
#else
	if ( ++line >= lines_max ) {
	    if ( pause_flg ) {
		printf("--- more ---"); fflush(stdout);
		ch = INKEY();
		printf("\r            \r"); fflush(stdout);
		if ( ch == '\033' )
		    return ERR;
	    }
	    line = 0;
	}
	dic_puts(p, color_flag ? NULL:stdout);
#endif	/* !MORE */
    }

#ifdef	MORE
    if ( fp != stdout )
	pclose(fp);
#endif

/*
    if ( color_flag ) {
	BOLD_OFF();
	ITALIC_OFF();
    }
*/

    if ( pause_flg ) {
	printf("Hit Return Key >"); fflush(stdout);
	ch = INKEY();
#ifndef	MORE
	printf("\r                 \r"); fflush(stdout);
#endif
    }

    return FALSE;
}
static	uchar	*pager_get_line(int line, POINT *tab, int *no, int max)
{
    uchar   *p;

    if ( dic_mem_flag )
	return NULL;
    while ( (p = dic_goto_line(line)) == NULL ) {
        while ( (p = dic_next_line()) == NULL ) {
    	    if ( *no >= max )
	        return "\n";
	    if ( dic_seek(tab[*no].block, tab[*no].offset) )
	        return NULL;
	    *no += 1;
	}
    }
    return p;
}
void	pager(POINT *tab, int max, int fg)
{
    int     ch, n;
    int     no = 0;
    int     line = 0;
    int     top = 0;
    uchar   *p;

    if ( no >= max )
	return;

#ifdef	CURSES
#ifdef	NEWS
    setlocale(LC_CTYPE, "");
#endif
    initscr();
    cbreak();
    noecho();
    scrollok(stdscr, TRUE);
    idlok(stdscr, TRUE);
    cols_max = COLS;
    lines_max = LINES;
#endif

    if ( !fg ) {
        dic_seek(tab[no].block, tab[no].offset);
        dic_init_line(TRUE);
    }

    no++;

    CUROFF();
    for ( n = 0 ; n < (lines_max - 1) ; n++ ) {
	if ( (p = pager_get_line(n, tab, &no, max)) == NULL )
	    goto ENDOF;
        LOCATE(0, n);
        dic_puts(p, NULL);
    }
    LOCATE(0, lines_max - 1);
    ERALINE();
    FLUSH();

    for ( ; ; ) {
	if ( color_flag ) {
	    if ( top != line ) {
/****************************
	        BOLD_OFF();
		ITALIC_OFF();
*****************************/
	        for ( n = 0 ; n < (lines_max - 1) ; n++ ) {
	            if ( (p = pager_get_line(line + n,
					tab, &no, max)) == NULL )
		        goto ENDOF;
	            LOCATE(0, n);
		    dic_puts(p, NULL);
	        }
	        LOCATE(0, lines_max - 1);
	        ERALINE();
	        FLUSH();
	        top = line;
	    }
	} else {
	    while ( top < line ) {
	        top++;
	        if ( (p = pager_get_line(top + lines_max - 2,
					tab, &no, max)) == NULL )
		    goto ENDOF;
	        FORSCROOL();
	        LOCATE(0, lines_max - 2);
	        dic_puts(p, NULL);
	        FLUSH();
	    }
	    while ( top > line ) {
	        top--;
	        if ( (p = pager_get_line(top, tab, &no, max)) == NULL )
		    goto ENDOF;
	        BACKSCROOL();
	        LOCATE(0, 0);
	        dic_puts(p, NULL);
	        LOCATE(0, lines_max - 1);
	        ERALINE();
	        FLUSH();
	    }
	}

	ch = GETCH();
	switch(ch) {
	case '\n': case '\r':
	case '\x1F':
	case 'x': case 'X': case 'X'-'@':
	case 'u': case 'U': case 'U'-'@':
	case 'j': case 'J': /* case 'J'-'@': */
	    line++;
	    break;
	case '\x1E':
	case 'e': case 'E': case 'E'-'@':
	case 'd': case 'D': case 'D'-'@':
	case 'k': case 'K': case 'K'-'@':
	    if ( line > 0 )
		line--;
	    break;
	case ' ':
	case 'c': case 'C': case 'C'-'@':
	case 'n': case 'N': case 'N'-'@':
	case 'f': case 'F': case 'F'-'@':
	    line += (lines_max - 3);
	    break;
	case '\b':
	case 'r': case 'R': case 'R'-'@':
	case 'b': case 'B': case 'B'-'@':
	case 'p': case 'P': case 'P'-'@':
	    if ( (line -= (lines_max - 3)) < 0 )
		line = 0;
	    break;
	case '\033':
	case 'q': case 'Q': case 'Q'-'@':
	    goto ENDOF;
	case 's': case 'S': case 'S'-'@':
	case 'l': case 'L': /* case 'L'-'@': */
	    if ( ext_out_fp != NULL ) {
	        for ( n = 0 ; n < (lines_max - 1) ; n++ ) {
	            if ( (p = pager_get_line(line + n,
					tab, &no, max)) == NULL )
		        goto ENDOF;
	            dic_puts(p, ext_out_fp);
		}
	    }
	    break;
	case 'L'-'@':
	    REFRESH();
	    break;
	}
    }
    ENDOF:

/*
    if ( color_flag ) {
	BOLD_OFF();
	ITALIC_OFF();
    }
*/

    LOCATE(0, lines_max - 1);
    CURON();
    FLUSH();

#ifdef	CURSES
    endwin();
#endif

    if ( dic_mem_flag )
	fprintf(stderr, "Memory Alloc Error\n");
}
int	more(POINT *tab, int max)
{
    int     n;
    uchar   *p;
#ifdef	MORE
    FILE    *fp;
#else
    int     ch;
    int     line = 0;
#endif

#ifdef	MORE
    if ( pause_flg == FALSE || (fp = popen(MORE, "w")) == NULL )
	fp = stdout;
#endif	/* MORE */

    for ( n = 0 ; n < max ; n++ ) {
	if ( dic_seek(tab[n].block, tab[n].offset) )
	    return ERR;
	dic_init_line(FALSE);
        while ( (p = dic_next_line()) != NULL ) {
#ifdef	MORE
	    if ( ferror(fp) )
		goto ENDOF;
	    dic_puts(p, fp);
#else
	    if ( ++line >= lines_max ) {
	        if ( pause_flg ) {
		    printf("--- more ---"); fflush(stdout);
		    ch = INKEY();
		    printf("\r            \r"); fflush(stdout);
		    if ( ch == '\033' )
		        return ERR;
	        }
	        line = 0;
	    }
	    dic_puts(p, color_flag ? NULL:stdout);
#endif
	    if ( ext_out_fp != NULL )
	        dic_puts(p, ext_out_fp);
	}
    }

#ifdef	MORE
ENDOF:
    if ( fp != stdout )
	pclose(fp);
#endif

    return FALSE;
}
