aboutsummaryrefslogblamecommitdiffstats
path: root/display.c
blob: bdf39d49e0ec46d9875d65466c68fd46d962d589 (plain) (tree)
1
2
3
4
5
6
7
8
                                                         





                                          
                





































































































                                                                                                                                             
                                                   











                                                
                                                   
















                                                       
                

                        
                                               




                              








                         


                                                  

                      















                                                                      
                     






                                       
                         





















                                                                                          










                                                                        












                                                                         
                                     


                                          
                                                                       











                                      
                






                                                
                                                   


















































                                                            
                                                               





















                                         
                

                            
                   
                            
                                                  
     
                                               






















                                                                           
                     

                  
                














                                               


















                                                                            









                                               
                     









                                 
                                                                            
                


















                                                                          
                                      
                  
                     
































































                                                       
                     


                    
                                  










                                                                   
                     


                   
                









                               
                     











                                 
                                                                            
                


















                                                                          
                                      
                  
                     




                                    
                                    



                                                        
                                                

























































                                                       
                     



























































                                                                                   
                     






                               
                   







































































                                                                                 
                                                                                             




















                                                                             
                                                   


                           
                                                                                 


                                
                



                                  
                











                                                          
                







                                                           
                             





                               
                                                              






                                                      
                               





                                    
                                                            


















                                                                      
                                



































                                                                 

                                                                          





                                                  
                               


















                                                  

                                                                  











































                                                                              
                                                                            
                               
                             

























































                                                                                            
                                          




                                  
                                           




                                     
                                          






                         
/* $Id: display.c,v 1.6 2001/11/21 19:24:35 ukai Exp $ */
#include <signal.h>
#include "fm.h"

#define MAX(a, b)  ((a) > (b) ? (a) : (b))
#define MIN(a, b)  ((a) < (b) ? (a) : (b))

#ifdef USE_COLOR

#define EFFECT_ANCHOR_START       effect_anchor_start()
#define EFFECT_ANCHOR_END         effect_anchor_end()
#define EFFECT_IMAGE_START        effect_image_start()
#define EFFECT_IMAGE_END          effect_image_end()
#define EFFECT_FORM_START         effect_form_start()
#define EFFECT_FORM_END           effect_form_end()
#define EFFECT_ACTIVE_START	  effect_active_start()
#define EFFECT_ACTIVE_END	  effect_active_end()
#define EFFECT_VISITED_START      effect_visited_start()
#define EFFECT_VISITED_END        effect_visited_end()

/* color: *     0  black *      1  red *        2  green *      3  yellow
 * *    4  blue *       5  magenta *    6  cyan *       7  white */

#define EFFECT_ANCHOR_START_C       setfcolor(anchor_color)
#define EFFECT_IMAGE_START_C        setfcolor(image_color)
#define EFFECT_FORM_START_C         setfcolor(form_color)
#define EFFECT_ACTIVE_START_C      (setfcolor(active_color), underline())
#define EFFECT_VISITED_START_C      setfcolor(visited_color)

#define EFFECT_IMAGE_END_C          setfcolor(basic_color)
#define EFFECT_ANCHOR_END_C         setfcolor(basic_color)
#define EFFECT_FORM_END_C           setfcolor(basic_color)
#define EFFECT_ACTIVE_END_C        (setfcolor(basic_color), underlineend())
#define EFFECT_VISITED_END_C        setfcolor(basic_color)

#define EFFECT_ANCHOR_START_M       underline()
#define EFFECT_ANCHOR_END_M         underlineend()
#define EFFECT_IMAGE_START_M        standout()
#define EFFECT_IMAGE_END_M          standend()
#define EFFECT_FORM_START_M         standout()
#define EFFECT_FORM_END_M           standend()
#define EFFECT_ACTIVE_START_NC      underline()
#define EFFECT_ACTIVE_END_NC        underlineend()
#define EFFECT_ACTIVE_START_M       bold()
#define EFFECT_ACTIVE_END_M         boldend()
#define EFFECT_VISITED_START_M      /**/
#define EFFECT_VISITED_END_M        /**/

#define define_effect(name_start,name_end,color_start,color_end,mono_start,mono_end) \
static void name_start { if (useColor) { color_start; } else { mono_start; }}\
static void name_end { if (useColor) { color_end; } else { mono_end; }}

define_effect(EFFECT_ANCHOR_START, EFFECT_ANCHOR_END, EFFECT_ANCHOR_START_C, EFFECT_ANCHOR_END_C, EFFECT_ANCHOR_START_M, EFFECT_ANCHOR_END_M)
define_effect(EFFECT_IMAGE_START, EFFECT_IMAGE_END, EFFECT_IMAGE_START_C, EFFECT_IMAGE_END_C, EFFECT_IMAGE_START_M, EFFECT_IMAGE_END_M)
define_effect(EFFECT_FORM_START, EFFECT_FORM_END, EFFECT_FORM_START_C, EFFECT_FORM_END_C, EFFECT_FORM_START_M, EFFECT_FORM_END_M)
static void EFFECT_ACTIVE_START
{
    if (useColor) {
	if (useActiveColor) {
#ifdef __EMX__
	    if(!getenv("WINDOWID"))
		setfcolor(active_color);
	    else
#endif
	    {
		EFFECT_ACTIVE_START_C;
	    }
	} else {
	    EFFECT_ACTIVE_START_NC;
	}
    } else {
	EFFECT_ACTIVE_START_M;
    }
}

static void EFFECT_ACTIVE_END
{
    if (useColor) {
	if (useActiveColor) {
	    EFFECT_ACTIVE_END_C;
	} else {
	    EFFECT_ACTIVE_END_NC;
	}
    } else {
	 EFFECT_ACTIVE_END_M;
    }
}

static void EFFECT_VISITED_START
{
    if (useVisitedColor) {
	if (useColor) {
	    EFFECT_VISITED_START_C;
	} else {
	    EFFECT_VISITED_START_M;
	}
    }
}

static void EFFECT_VISITED_END
{
    if (useVisitedColor) {
	if (useColor) {
	    EFFECT_VISITED_END_C;
	} else {
	    EFFECT_VISITED_END_M;
	}
    }
}

#else				/* not USE_COLOR */

#define EFFECT_ANCHOR_START       underline()
#define EFFECT_ANCHOR_END         underlineend()
#define EFFECT_IMAGE_START        standout()
#define EFFECT_IMAGE_END          standend()
#define EFFECT_FORM_START         standout()
#define EFFECT_FORM_END           standend()
#define EFFECT_ACTIVE_START       bold()
#define EFFECT_ACTIVE_END         boldend()
#define EFFECT_VISITED_START      /**/
#define EFFECT_VISITED_END        /**/

#endif				/* not USE_COLOR */


#ifndef KANJI_SYMBOLS
static char g_rule[] = "ntwluxkavmqajaaa";
#endif				/* not KANJI_SYMBOLS */

/* 
 * Terminate routine.
 */

void
fmTerm(void)
{
    if (fmInitialized) {
	move(LASTLINE, 0);
	clrtoeolx();
	refresh();
#ifdef USE_MOUSE
	if (use_mouse)
	    mouse_end();
#endif				/* USE_MOUSE */
	reset_tty();
	fmInitialized = FALSE;
    }
}


/* 
 * Initialize routine.
 */
void
fmInit(void)
{
    if (!fmInitialized) {
	initscr();
#if defined( __CYGWIN__ ) && defined( JP_CHARSET )
	init_win32_console_handle();
#endif
	term_raw();
	term_noecho();
    }
    fmInitialized = TRUE;
}

/* 
 * Display some lines.
 */
static Line *cline = NULL;
static int ccolumn = -1;

static int ulmode = 0, somode = 0, bomode = 0;
static int anch_mode = 0, emph_mode = 0, imag_mode = 0, form_mode = 0,
 active_mode = 0, visited_mode = 0;
#ifndef KANJI_SYMBOLS
static int graph_mode = 0;
#endif				/* not KANJI_SYMBOLS */
#ifdef USE_ANSI_COLOR
static Linecolor color_mode = 0;
#endif

#ifdef BUFINFO
static Buffer *save_current_buf = NULL;
#endif

int in_check_url = FALSE;

void
displayBuffer(Buffer * buf, int mode)
{
    Str msg;
    Anchor *aa = NULL;

    if (in_check_url)
	return;
    if (buf->topLine == NULL && readBufferCache(buf) == 0) {	/* clear_buffer */
	mode = B_FORCE_REDRAW;
    }

    if (buf->width == 0)
	buf->width = COLS;
    if (buf->height == 0)
	buf->height = LASTLINE + 1;
    if (buf->width != INIT_BUFFER_WIDTH && buf->type && !strcmp(buf->type, "text/html")) {
	in_check_url = TRUE;
	reshapeBuffer(buf);
	in_check_url = FALSE;
    }
    if (showLineNum) {
	if (buf->lastLine && buf->lastLine->real_linenumber > 0)
	    buf->rootX = (int)(log(buf->lastLine->real_linenumber + 0.1)
		/ log(10)) + 2;
	if (buf->rootX < 5)
	    buf->rootX = 5;
	if (buf->rootX > COLS)
	    buf->rootX = COLS;
    } else
	buf->rootX = 0;
    buf->COLS = COLS - buf->rootX;
    if (mode == B_FORCE_REDRAW ||
	mode == B_SCROLL ||
	cline != buf->topLine ||
	ccolumn != buf->currentColumn) {
	if (mode == B_SCROLL && cline && buf->currentColumn == ccolumn) {
	    int n = buf->topLine->linenumber - cline->linenumber;
	    if (n > 0 && n < LASTLINE) {
		move(LASTLINE, 0);
		clrtoeolx();
		refresh();
		scroll(n);
	    }
	    else if (n < 0 && n > -LASTLINE) {
#if defined(__CYGWIN__) && LANG == JA
		move(LASTLINE + n + 1, 0);
		clrtoeolx();
		refresh();
#endif				/* defined(__CYGWIN__) && LANG == JA */
		rscroll(-n);
	    }
	    redrawNLine(buf, n);
	}
	else
	    redrawBuffer(buf);
	cline = buf->topLine;
	ccolumn = buf->currentColumn;
    }
    if (buf->topLine == NULL)
	buf->topLine = buf->firstLine;

#ifdef USE_MOUSE
    if (use_mouse)
#if LANG == JA
	msg = Strnew_charp("�㢬��");
#else				/* LANG != JA */
	msg = Strnew_charp("<=UpDn ");
#endif				/* LANG != JA */
    else
#endif				/* not USE_MOUSE */
	msg = Strnew();
    Strcat_charp(msg, "Viewing <");
    Strcat_charp(msg, buf->buffername);
    if (displayLink)
	aa = retrieveCurrentAnchor(buf);
    if (aa) {
	ParsedURL url;
	Str s;
	int l;
	parseURL2(aa->url, &url, baseURL(buf));
	s = parsedURL2Str(&url);
	l = buf->width - 2;
	if (s->length > l) {
	    if (l >= 4) {
		msg = Strsubstr(s, 0, (l - 2) / 2);
#if LANG == JA
		Strcat_charp(msg, "��");
#else				/* LANG != JA */
		Strcat_charp(msg, "..");
#endif				/* LANG != JA */
		l = buf->width - msg->length;
		Strcat(msg, Strsubstr(s, s->length - l, l));
	    } else {
		msg = s;
	    }
	} else {
	    l -= s->length;
	    if (msg->length > l) {
#ifdef JP_CHARSET
		char *bn = msg->ptr;
		int i, j;
		for (i = 0; bn[i]; i += j) {
		    j = get_mclen(get_mctype(&bn[i]));
		    if (i + j > l)
			break;
		}
		l = i;
#endif
		Strtruncate(msg, l);
	    }
	    Strcat_charp(msg, "> ");
	    Strcat(msg, s);
	}
    } else {
	Strcat_charp(msg, ">");
    }
    if (buf->firstLine == NULL) {
	Strcat_charp(msg, "\tNo Line");
	clear();
    }
    standout();
    message(msg->ptr, buf->cursorX + buf->rootX, buf->cursorY);
    standend();
    refresh();
#ifdef BUFINFO
    if (Currentbuf != save_current_buf) {
	saveBufferInfo();
	save_current_buf = Currentbuf;
    }
#endif
}

void
redrawBuffer(Buffer * buf)
{
    redrawNLine(buf, LASTLINE);
}

void
redrawNLine(Buffer * buf, int n)
{
    Line *l, *l0;
    int i;

#ifdef USE_COLOR
    if (useColor) {
	EFFECT_ANCHOR_END_C;
#ifdef USE_BG_COLOR
	setbcolor(bg_color);
#endif				/* USE_BG_COLOR */
    }
#endif				/* USE_COLOR */
    for (i = 0, l = buf->topLine; i < LASTLINE; i++) {
	if (i >= LASTLINE - n || i < -n)
	    l0 = redrawLine(buf, l, i);
	else {
	    l0 = (l) ? l->next : NULL;
	}
	if (l0 == NULL && l == NULL)
	    break;
	l = l0;
    }
    if (n > 0)
	clrtobotx();
}

#define addKanji(pc,pr) (addChar((pc)[0],(pr)[0]),addChar((pc)[1],(pr)[1]))

Line *
redrawLine(Buffer * buf, Line * l, int i)
{
    int j, pos, rcol, ncol, delta;
    int column = buf->currentColumn;
    char *p;
    Lineprop *pr;
#ifdef USE_ANSI_COLOR
    Linecolor *pc;
#endif
#ifdef USE_COLOR
    Anchor *a;
    ParsedURL url;
    int k, vpos = -1;
#endif

    if (l == NULL) {
	if (buf->pagerSource) {
	    l = getNextPage(buf, LASTLINE - i);
	    if (l == NULL)
		return NULL;
	}
	else
	    return NULL;
    }
    move(i, 0);
    if (showLineNum) {
	char tmp[16];
	if (! buf->rootX) {
	    if (buf->lastLine->real_linenumber > 0)
		buf->rootX = (int)(log(buf->lastLine->real_linenumber + 0.1)
			/ log(10)) + 2;
	    if (buf->rootX < 5)
		buf->rootX = 5;
	    if (buf->rootX > COLS)
		buf->rootX = COLS;
	    buf->COLS = COLS - buf->rootX;
	}
	if (l->real_linenumber)
	    sprintf(tmp, "%*d:", buf->rootX - 1, l->real_linenumber);
	else
	    sprintf(tmp, "%*s ", buf->rootX - 1, "");
	addstr(tmp);
    }
    move(i, buf->rootX);
    if (l->width < 0)
	l->width = COLPOS(l, l->len);
    if (l->len == 0 || l->width - 1 < column) {
	clrtoeolx();
	return l->next;
    }
    /* need_clrtoeol(); */
    pos = columnPos(l, column);
    p = &(l->lineBuf[pos]);
    pr = &(l->propBuf[pos]);
#ifdef USE_ANSI_COLOR
    if (useColor && l->colorBuf)
	pc = &(l->colorBuf[pos]);
    else
	pc = NULL;
#endif
    rcol = COLPOS(l, pos);

#ifndef JP_CHARSET
    delta = 1;
#endif
    for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j += delta) {
#ifdef USE_COLOR
	if (useVisitedColor && vpos <= pos + j && !(pr[j] & PE_VISITED)) {
	    a = retrieveAnchor(buf->href, l->linenumber, pos + j);
	    if (a) {
		parseURL2(a->url, &url, baseURL(buf));
		if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
		    for (k = a->start.pos; k < a->end.pos; k++)
			pr[k - pos] |= PE_VISITED;
		}
		vpos = a->end.pos;
	    }
	}
#endif
#ifdef JP_CHARSET
	if (CharType(pr[j]) == PC_KANJI1)
	    delta = 2;
	else
	    delta = 1;
#endif
	ncol = COLPOS(l, pos + j + delta);
	if (ncol - column > buf->COLS)
	    break;
#ifdef USE_ANSI_COLOR
	if (pc)
	    do_color(pc[j]);
#endif
	if (rcol < column) {
	    for (rcol = column; rcol < ncol; rcol++)
		addChar(' ', 0);
	    continue;
	}
	if (p[j] == '\t') {
	    for (; rcol < ncol; rcol++)
		addChar(' ', 0);
	}
#ifdef JP_CHARSET
	else if (delta == 2) {
	    addKanji(&p[j], &pr[j]);
	}
#endif
	else {
	    addChar(p[j], pr[j]);
	}
	rcol = ncol;
    }
    if (somode) {
	somode = FALSE;
	standend();
    }
    if (ulmode) {
	ulmode = FALSE;
	underlineend();
    }
    if (bomode) {
	bomode = FALSE;
	boldend();
    }
    if (emph_mode) {
	emph_mode = FALSE;
	boldend();
    }

    if (anch_mode) {
	anch_mode = FALSE;
	EFFECT_ANCHOR_END;
    }
    if (imag_mode) {
	imag_mode = FALSE;
	EFFECT_IMAGE_END;
    }
    if (form_mode) {
	form_mode = FALSE;
	EFFECT_FORM_END;
    }
    if (visited_mode) {
	visited_mode = FALSE;
	EFFECT_VISITED_END;
    }
    if (active_mode) {
	active_mode = FALSE;
	EFFECT_ACTIVE_END;
    }
#ifndef KANJI_SYMBOLS
    if (graph_mode) {
	graph_mode = FALSE;
	graphend();
    }
#endif				/* not KANJI_SYMBOLS */
#ifdef USE_ANSI_COLOR
    if (color_mode)
	do_color(0);
#endif
    if (rcol - column < buf->COLS)
	clrtoeolx();
    return l->next;
}

int
redrawLineRegion(Buffer * buf, Line * l, int i, int bpos, int epos)
{
    int j, pos, rcol, ncol, delta;
    int column = buf->currentColumn;
    char *p;
    Lineprop *pr;
#ifdef USE_ANSI_COLOR
    Linecolor *pc;
#endif
    int bcol, ecol;
#ifdef USE_COLOR
    Anchor *a;
    ParsedURL url;
    int k, vpos = -1;
#endif

    if (l == NULL)
	return 0;
    pos = columnPos(l, column);
    p = &(l->lineBuf[pos]);
    pr = &(l->propBuf[pos]);
#ifdef USE_ANSI_COLOR
    if (useColor && l->colorBuf)
	pc = &(l->colorBuf[pos]);
    else
	pc = NULL;
#endif
    rcol = COLPOS(l, pos);
    bcol = bpos - pos;
    ecol = epos - pos;

#ifndef JP_CHARSET
    delta = 1;
#endif
    for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j += delta) {
#ifdef USE_COLOR
	if (useVisitedColor && vpos <= pos + j && !(pr[j] & PE_VISITED)) {
	    a = retrieveAnchor(buf->href, l->linenumber, pos + j);
	    if (a) {
		parseURL2(a->url, &url, baseURL(buf));
		if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
		    for (k = a->start.pos; k < a->end.pos; k++)
			pr[k - pos] |= PE_VISITED;
		}
		vpos = a->end.pos;
	    }
	}
#endif
#ifdef JP_CHARSET
	if (CharType(pr[j]) == PC_KANJI1)
	    delta = 2;
	else
	    delta = 1;
#endif
	ncol = COLPOS(l, pos + j + delta);
	if (ncol - column > buf->COLS)
	    break;
#ifdef USE_ANSI_COLOR
	if (pc)
	    do_color(pc[j]);
#endif
	if (j >= bcol && j < ecol) {
	    if (rcol < column) {
		move(i, buf->rootX);
		for (rcol = column; rcol < ncol; rcol++)
		    addChar(' ', 0);
		continue;
	    }
	    move(i, rcol - column + buf->rootX);
	    if (p[j] == '\t') {
		for (; rcol < ncol; rcol++)
		    addChar(' ', 0);
	    }
#ifdef JP_CHARSET
	    else if (delta == 2) {
		addKanji(&p[j], &pr[j]);
	    }
#endif
	    else {
		addChar(p[j], pr[j]);
	    }
	}
	rcol = ncol;
    }
    if (somode) {
	somode = FALSE;
	standend();
    }
    if (ulmode) {
	ulmode = FALSE;
	underlineend();
    }
    if (bomode) {
	bomode = FALSE;
	boldend();
    }
    if (emph_mode) {
	emph_mode = FALSE;
	boldend();
    }

    if (anch_mode) {
	anch_mode = FALSE;
	EFFECT_ANCHOR_END;
    }
    if (imag_mode) {
	imag_mode = FALSE;
	EFFECT_IMAGE_END;
    }
    if (form_mode) {
	form_mode = FALSE;
	EFFECT_FORM_END;
    }
    if (visited_mode) {
	visited_mode = FALSE;
	EFFECT_VISITED_END;
    }
    if (active_mode) {
	active_mode = FALSE;
	EFFECT_ACTIVE_END;
    }
#ifndef KANJI_SYMBOLS
    if (graph_mode) {
	graph_mode = FALSE;
	graphend();
    }
#endif				/* not KANJI_SYMBOLS */
#ifdef USE_ANSI_COLOR
    if (color_mode)
	do_color(0);
#endif
    return rcol - column;
}

#define do_effect1(effect,modeflag,action_start,action_end) \
if (m & effect) { \
    if (!modeflag) { \
	action_start; \
	modeflag = TRUE; \
    } \
}

#define do_effect2(effect,modeflag,action_start,action_end) \
if (modeflag) { \
    action_end; \
    modeflag = FALSE; \
}

void
do_effects(Lineprop m)
{
    /* effect end */
    do_effect2(PE_UNDER, ulmode, underline(), underlineend());
    do_effect2(PE_STAND, somode, standout(), standend());
    do_effect2(PE_BOLD, bomode, bold(), boldend());
    do_effect2(PE_EMPH, emph_mode, bold(), boldend());
    do_effect2(PE_ANCHOR, anch_mode, EFFECT_ANCHOR_START, EFFECT_ANCHOR_END);
    do_effect2(PE_IMAGE, imag_mode, EFFECT_IMAGE_START, EFFECT_IMAGE_END);
    do_effect2(PE_FORM, form_mode, EFFECT_FORM_START, EFFECT_FORM_END);
    do_effect2(PE_VISITED, visited_mode, EFFECT_VISITED_START, EFFECT_VISITED_END);
    do_effect2(PE_ACTIVE, active_mode, EFFECT_ACTIVE_START, EFFECT_ACTIVE_END);
#ifndef KANJI_SYMBOLS
    if (graph_mode) {
	graphend();
	graph_mode = FALSE;
    }
#endif				/* not KANJI_SYMBOLS */

    /* effect start */
    do_effect1(PE_UNDER, ulmode, underline(), underlineend());
    do_effect1(PE_STAND, somode, standout(), standend());
    do_effect1(PE_BOLD, bomode, bold(), boldend());
    do_effect1(PE_EMPH, emph_mode, bold(), boldend());
    do_effect1(PE_ANCHOR, anch_mode, EFFECT_ANCHOR_START, EFFECT_ANCHOR_END);
    do_effect1(PE_IMAGE, imag_mode, EFFECT_IMAGE_START, EFFECT_IMAGE_END);
    do_effect1(PE_FORM, form_mode, EFFECT_FORM_START, EFFECT_FORM_END);
    do_effect1(PE_VISITED, visited_mode, EFFECT_VISITED_START, EFFECT_VISITED_END);
    do_effect1(PE_ACTIVE, active_mode, EFFECT_ACTIVE_START, EFFECT_ACTIVE_END);
#ifndef KANJI_SYMBOLS
    if (m & PC_RULE) {
	if (!graph_mode && graph_ok()) {
	    graphstart();
	    graph_mode = TRUE;
	}
    }
#endif				/* not KANJI_SYMBOLS */
}

#ifdef USE_ANSI_COLOR
void
do_color(Linecolor c)
{
    if (c & 0x8)
	setfcolor(c & 0x7);
    else if (color_mode & 0x8)
	setfcolor(basic_color);
#ifdef USE_BG_COLOR
    if (c & 0x80)
	setbcolor((c >> 4) & 0x7);
    else if (color_mode & 0x80)
	setbcolor(bg_color);
#endif
    color_mode = c;
}
#endif

void
addChar(char c, Lineprop mode)
{
    Lineprop m = CharEffect(mode);

#ifdef JP_CHARSET
    if (CharType(mode) != PC_KANJI2)
#endif				/* JP_CHARSET */
    do_effects(m);
#ifndef KANJI_SYMBOLS
    if (m & PC_RULE) {
	if (graph_mode)
	    addch(g_rule[c & 0xF]);
	else
	    addch(alt_rule[c & 0xF]);
    } else
#endif				/* not KANJI_SYMBOLS */
    if (IS_UNPRINTABLE_ASCII(c, mode)) {
	addstr(Sprintf("\\%3o", (unsigned char)c)->ptr);
    }
    else if (c == '\t') {
	addch(c);
    }
    else if (c == DEL_CODE)
	addstr("^?");
    else if (IS_UNPRINTABLE_CONTROL(c, mode)) {	/* Control code */
	addch('^');
	addch(c + '@');
    }
    else if (c != '\n')
	addch(c);
    else	/* \n */
	addch(' ');
}

GeneralList *message_list = NULL;

void
record_err_message(char *s)
{
    if (fmInitialized) {
	if (!message_list)
	    message_list = newGeneralList();
	if (message_list->nitem >= LINES)
	    popValue(message_list);
	pushValue(message_list, allocStr(s, 0));
    }
}

/* 
 * List of error messages
 */
Buffer *
message_list_panel(void)
{
    Str tmp = Strnew_size(LINES * COLS);
    ListItem *p;

    Strcat_charp(tmp,
		 "<html><head><title>List of error messages</title></head><body>"
		 "<h1>List of error messages</h1><table cellpadding=0>\n");
    if (message_list)
      for (p = message_list->last ; p ; p = p->prev)
	Strcat_m_charp(tmp, "<tr><td><pre>", html_quote(p->ptr), "</pre></td></tr>\n", NULL);
    else
      Strcat_charp(tmp, "<tr><td>(no message recorded)</td></tr>\n");
    Strcat_charp(tmp, "</table></body></html>");
    return loadHTMLString(tmp);
}

void
message(char *s, int return_x, int return_y)
{
    if (!fmInitialized)
	return;
    move(LASTLINE, 0);
    addnstr(s, COLS - 1);
    clrtoeolx();
    move(return_y, return_x);
}

void
disp_message_nsec(char *s, int redraw_current, int sec, int purge, int mouse)
{
    if (!fmInitialized) {
	fprintf(stderr, "%s\n", conv_to_system(s));
	return;
    }
    if (Currentbuf != NULL)
	message(s, Currentbuf->cursorX + Currentbuf->rootX, Currentbuf->cursorY);
    else
	message(s, LASTLINE, 0);
    refresh();
#ifdef USE_MOUSE
    if (mouse && use_mouse)
	mouse_active();
#endif
    sleep_till_anykey(sec, purge);
#ifdef USE_MOUSE
    if (mouse && use_mouse)
	mouse_inactive();
#endif
    if (Currentbuf != NULL && redraw_current)
	displayBuffer(Currentbuf, B_NORMAL);
}

void
disp_message(char *s, int redraw_current)
{
    disp_message_nsec(s, redraw_current, 10, FALSE, TRUE);
}
#ifdef USE_MOUSE
void
disp_message_nomouse(char *s, int redraw_current)
{
    disp_message_nsec(s, redraw_current, 10, FALSE, FALSE);
}
#endif

void
cursorUp(Buffer * buf, int n)
{
    if (buf->firstLine == NULL)
	return;
    if (buf->cursorY > 0)
	cursorUpDown(buf, -1);
    else {
       buf->topLine = lineSkip(buf, buf->topLine, - n, FALSE);
	if (buf->currentLine->prev != NULL)
	    buf->currentLine = buf->currentLine->prev;
	arrangeLine(buf);
    }
}

void
cursorDown(Buffer * buf, int n)
{
    if (buf->firstLine == NULL)
	return;
    if (buf->cursorY < LASTLINE - 1)
	cursorUpDown(buf, 1);
    else {
       buf->topLine = lineSkip(buf, buf->topLine, n, FALSE);
	if (buf->currentLine->next != NULL)
	    buf->currentLine = buf->currentLine->next;
	arrangeLine(buf);
    }
}

void
cursorUpDown(Buffer * buf, int n)
{
    Line *cl = buf->currentLine;

    if (buf->firstLine == NULL)
	return;
    if ((buf->currentLine = currentLineSkip(buf, cl, n, FALSE)) == cl)
	return;
    arrangeLine(buf);
}

void
cursorRight(Buffer * buf, int n)
{
    int i, delta = 1, cpos, vpos2;
    Line *l = buf->currentLine;
    Lineprop *p;

    if (buf->firstLine == NULL)
	return;
    if (buf->pos == l->len)
	return;
    i = buf->pos;
    p = l->propBuf;
#ifdef JP_CHARSET
    if (CharType(p[i]) == PC_KANJI1)
	delta = 2;
#endif				/* JP_CHARSET */
    if (i + delta < l->len) {
	buf->pos = i + delta;
    }
    else if (l->len == 0) {
        buf->pos = 0;
    }
    else {
        buf->pos = l->len -1;
#ifdef JP_CHARSET
        if (CharType(p[buf->pos]) == PC_KANJI2)
            buf->pos--;
#endif                          /* JP_CHARSET */
    }
    cpos = COLPOS(l, buf->pos);
    buf->visualpos = cpos - buf->currentColumn;
    delta = 1;
#ifdef JP_CHARSET
    if (CharType(p[buf->pos]) == PC_KANJI1)
        delta = 2;
#endif                          /* JP_CHARSET */
    vpos2 = COLPOS(l, buf->pos + delta) - buf->currentColumn - 1;
    if (vpos2 >= buf->COLS && n) {
       columnSkip(buf, n + (vpos2 - buf->COLS) - (vpos2 - buf->COLS) % n);
       buf->visualpos = cpos - buf->currentColumn;
    }
    buf->cursorX = buf->visualpos;
}

void
cursorLeft(Buffer * buf, int n)
{
    int i, delta = 1, cpos;
    Line *l = buf->currentLine;
    Lineprop *p;

    if (buf->firstLine == NULL)
	return;
    i = buf->pos;
    p = l->propBuf;
#ifdef JP_CHARSET
    if (i >= 2 && CharType(p[i - 1]) == PC_KANJI2)
	delta = 2;
#endif				/* JP_CHARSET */
    if (i > delta)
	buf->pos = i - delta;
    else
	buf->pos = 0;
    cpos = COLPOS(l, buf->pos);
    buf->visualpos = cpos - buf->currentColumn;
    if (buf->visualpos < 0 && n) {
       columnSkip(buf, - n + buf->visualpos - buf->visualpos % n);
	buf->visualpos = cpos - buf->currentColumn;
    }
    buf->cursorX = buf->visualpos;
}

void
cursorHome(Buffer * buf)
{
    buf->visualpos = 0;
    buf->cursorX = buf->cursorY = 0;
}


/* 
 * Arrange line,column and cursor position according to current line and
 * current position.
 */
void
arrangeCursor(Buffer * buf)
{
    int col,col2;
    int delta = 1;
    if (buf == NULL || buf->currentLine == NULL)
	return;
    /* Arrange line */
    if (buf->currentLine->linenumber - buf->topLine->linenumber >= LASTLINE ||
	buf->currentLine->linenumber < buf->topLine->linenumber) {
	buf->topLine = buf->currentLine;
    }
    /* Arrange column */
    if (buf->currentLine->len == 0)
	buf->pos = 0;
    else if (buf->pos >= buf->currentLine->len)
	buf->pos = buf->currentLine->len - 1;
#ifdef JP_CHARSET
    if (CharType(buf->currentLine->propBuf[buf->pos]) == PC_KANJI2)
	buf->pos--;
#endif				/* JP_CHARSET */
    col = COLPOS(buf->currentLine, buf->pos);
#ifdef JP_CHARSET
    if (CharType(buf->currentLine->propBuf[buf->pos]) == PC_KANJI1)
        delta = 2;
#endif                         /* JP_CHARSET */
    col2 = COLPOS(buf->currentLine, buf->pos + delta);
    if (col < buf->currentColumn || col2 > buf->COLS + buf->currentColumn) {
	buf->currentColumn = 0;
        if (col2 > buf->COLS)
	    columnSkip(buf, col);
    }
    /* Arrange cursor */
    buf->cursorY = buf->currentLine->linenumber - buf->topLine->linenumber;
    buf->visualpos = buf->cursorX = COLPOS(buf->currentLine, buf->pos) - buf->currentColumn;
#ifdef DISPLAY_DEBUG
    fprintf(stderr, "arrangeCursor: column=%d, cursorX=%d, visualpos=%d, pos=%d, len=%d\n",
	    buf->currentColumn, buf->cursorX, buf->visualpos,
	    buf->pos, buf->currentLine->len);
#endif
}

void
arrangeLine(Buffer * buf)
{
    int i, cpos;

    if (buf->firstLine == NULL)
	return;
    buf->cursorY = buf->currentLine->linenumber - buf->topLine->linenumber;
    i = columnPos(buf->currentLine, buf->currentColumn + buf->visualpos);
    cpos = COLPOS(buf->currentLine, i) - buf->currentColumn;
    if (cpos >= 0) {
	buf->cursorX = cpos;
	buf->pos = i;
    }
    else if (Currentbuf->currentLine->len > i) {
	int delta = 1;
#ifdef JP_CHARSET
	if (Currentbuf->currentLine->len > i + 1 &&
	    CharType(buf->currentLine->propBuf[i + 1]) == PC_KANJI2)
	    delta = 2;
#endif
	buf->cursorX = 0;
	buf->pos = i;
	if (COLPOS(buf->currentLine, i + delta) <= buf->currentColumn)
	    buf->pos += delta;
    }
    else {
	buf->cursorX = 0;
	buf->pos = 0;
    }
#ifdef DISPLAY_DEBUG
    fprintf(stderr, "arrangeLine: column=%d, cursorX=%d, visualpos=%d, pos=%d, len=%d\n",
	    buf->currentColumn, buf->cursorX, buf->visualpos,
	    buf->pos, buf->currentLine->len);
#endif
}

void
cursorXY(Buffer * buf, int x, int y)
{
    int oldX;

    cursorUpDown(buf, y - buf->cursorY);

    if (buf->cursorX > x) {
	while (buf->cursorX > x)
           cursorLeft(buf, buf->COLS / 2);
    }
    else if (buf->cursorX < x) {
	while (buf->cursorX < x) {
	    oldX = buf->cursorX;

           cursorRight(buf, buf->COLS / 2);

	    if (oldX == buf->cursorX)
		break;
	}
	if (buf->cursorX > x)
           cursorLeft(buf, buf->COLS / 2);
    }
}

/* Local Variables:    */
/* c-basic-offset: 4   */
/* tab-width: 8        */
/* End:                */