1 /* $Id: display.c,v 1.71 2010/07/18 14:10:09 htrb Exp $ */
2 #include <signal.h>
3 #include "fm.h"
4 
5 /* *INDENT-OFF* */
6 #ifdef USE_COLOR
7 
8 #define EFFECT_ANCHOR_START       effect_anchor_start()
9 #define EFFECT_ANCHOR_END         effect_anchor_end()
10 #define EFFECT_IMAGE_START        effect_image_start()
11 #define EFFECT_IMAGE_END          effect_image_end()
12 #define EFFECT_FORM_START         effect_form_start()
13 #define EFFECT_FORM_END           effect_form_end()
14 #define EFFECT_ACTIVE_START	  effect_active_start()
15 #define EFFECT_ACTIVE_END	  effect_active_end()
16 #define EFFECT_VISITED_START      effect_visited_start()
17 #define EFFECT_VISITED_END        effect_visited_end()
18 #define EFFECT_MARK_START         effect_mark_start()
19 #define EFFECT_MARK_END           effect_mark_end()
20 
21 /*-
22  * color:
23  *     0  black
24  *     1  red
25  *     2  green
26  *     3  yellow
27  *     4  blue
28  *     5  magenta
29  *     6  cyan
30  *     7  white
31  */
32 
33 #define EFFECT_ANCHOR_START_C       setfcolor(anchor_color)
34 #define EFFECT_IMAGE_START_C        setfcolor(image_color)
35 #define EFFECT_FORM_START_C         setfcolor(form_color)
36 #define EFFECT_ACTIVE_START_C      (setfcolor(active_color), underline())
37 #define EFFECT_VISITED_START_C      setfcolor(visited_color)
38 #ifdef USE_BG_COLOR
39 #define EFFECT_MARK_START_C         setbcolor(mark_color)
40 #else
41 #define EFFECT_MARK_START_C         standout()
42 #endif
43 
44 #define EFFECT_IMAGE_END_C          setfcolor(basic_color)
45 #define EFFECT_ANCHOR_END_C         setfcolor(basic_color)
46 #define EFFECT_FORM_END_C           setfcolor(basic_color)
47 #define EFFECT_ACTIVE_END_C        (setfcolor(basic_color), underlineend())
48 #define EFFECT_VISITED_END_C        setfcolor(basic_color)
49 #ifdef USE_BG_COLOR
50 #define EFFECT_MARK_END_C           setbcolor(bg_color)
51 #else
52 #define EFFECT_MARK_END_C           standend()
53 #endif
54 
55 #define EFFECT_ANCHOR_START_M       underline()
56 #define EFFECT_ANCHOR_END_M         underlineend()
57 #define EFFECT_IMAGE_START_M        standout()
58 #define EFFECT_IMAGE_END_M          standend()
59 #define EFFECT_FORM_START_M         standout()
60 #define EFFECT_FORM_END_M           standend()
61 #define EFFECT_ACTIVE_START_NC      underline()
62 #define EFFECT_ACTIVE_END_NC        underlineend()
63 #define EFFECT_ACTIVE_START_M       bold()
64 #define EFFECT_ACTIVE_END_M         boldend()
65 #define EFFECT_VISITED_START_M /**/
66 #define EFFECT_VISITED_END_M /**/
67 #define EFFECT_MARK_START_M         standout()
68 #define EFFECT_MARK_END_M           standend()
69 #define define_effect(name_start,name_end,color_start,color_end,mono_start,mono_end) \
70 static void name_start { if (useColor) { color_start; } else { mono_start; }}\
71 static void name_end { if (useColor) { color_end; } else { mono_end; }}
72 
define_effect(EFFECT_ANCHOR_START,EFFECT_ANCHOR_END,EFFECT_ANCHOR_START_C,EFFECT_ANCHOR_END_C,EFFECT_ANCHOR_START_M,EFFECT_ANCHOR_END_M)73 define_effect(EFFECT_ANCHOR_START, EFFECT_ANCHOR_END, EFFECT_ANCHOR_START_C,
74 	      EFFECT_ANCHOR_END_C, EFFECT_ANCHOR_START_M, EFFECT_ANCHOR_END_M)
75 define_effect(EFFECT_IMAGE_START, EFFECT_IMAGE_END, EFFECT_IMAGE_START_C,
76 	      EFFECT_IMAGE_END_C, EFFECT_IMAGE_START_M, EFFECT_IMAGE_END_M)
77 define_effect(EFFECT_FORM_START, EFFECT_FORM_END, EFFECT_FORM_START_C,
78 	      EFFECT_FORM_END_C, EFFECT_FORM_START_M, EFFECT_FORM_END_M)
79 define_effect(EFFECT_MARK_START, EFFECT_MARK_END, EFFECT_MARK_START_C,
80 	      EFFECT_MARK_END_C, EFFECT_MARK_START_M, EFFECT_MARK_END_M)
81 
82 /*****************/
83 static void
84 EFFECT_ACTIVE_START
85 {
86     if (useColor) {
87 	if (useActiveColor) {
88 #ifdef __EMX__
89 	    if(!getenv("WINDOWID"))
90 		setfcolor(active_color);
91 	    else
92 #endif
93 	    {
94 		EFFECT_ACTIVE_START_C;
95 	    }
96 	} else {
97 	    EFFECT_ACTIVE_START_NC;
98 	}
99     } else {
100 	EFFECT_ACTIVE_START_M;
101     }
102 }
103 
104 static void
105 EFFECT_ACTIVE_END
106 {
107     if (useColor) {
108 	if (useActiveColor) {
109 	    EFFECT_ACTIVE_END_C;
110 	} else {
111 	    EFFECT_ACTIVE_END_NC;
112 	}
113     } else {
114 	EFFECT_ACTIVE_END_M;
115     }
116 }
117 
118 static void
119 EFFECT_VISITED_START
120 {
121     if (useVisitedColor) {
122 	if (useColor) {
123 	    EFFECT_VISITED_START_C;
124 	} else {
125 	    EFFECT_VISITED_START_M;
126 	}
127     }
128 }
129 
130 static void
131 EFFECT_VISITED_END
132 {
133     if (useVisitedColor) {
134 	if (useColor) {
135 	    EFFECT_VISITED_END_C;
136 	} else {
137 	    EFFECT_VISITED_END_M;
138 	}
139     }
140 }
141 
142 #else				/* not USE_COLOR */
143 
144 #define EFFECT_ANCHOR_START       underline()
145 #define EFFECT_ANCHOR_END         underlineend()
146 #define EFFECT_IMAGE_START        standout()
147 #define EFFECT_IMAGE_END          standend()
148 #define EFFECT_FORM_START         standout()
149 #define EFFECT_FORM_END           standend()
150 #define EFFECT_ACTIVE_START       bold()
151 #define EFFECT_ACTIVE_END         boldend()
152 #define EFFECT_VISITED_START /**/
153 #define EFFECT_VISITED_END /**/
154 #define EFFECT_MARK_START         standout()
155 #define EFFECT_MARK_END           standend()
156 #endif				/* not USE_COLOR */
157 /* *INDENT-ON* */
158 
159 void
fmTerm(void)160 fmTerm(void)
161 {
162     if (fmInitialized) {
163 	move(LASTLINE, 0);
164 	clrtoeolx();
165 	refresh();
166 #ifdef USE_IMAGE
167 	if (activeImage)
168 	    loadImage(NULL, IMG_FLAG_STOP);
169 #endif
170 #ifdef USE_MOUSE
171 	if (use_mouse)
172 	    mouse_end();
173 #endif				/* USE_MOUSE */
174 	reset_tty();
175 	fmInitialized = FALSE;
176     }
177 }
178 
179 
180 /*
181  * Initialize routine.
182  */
183 void
fmInit(void)184 fmInit(void)
185 {
186     if (!fmInitialized) {
187 	initscr();
188 	term_raw();
189 	term_noecho();
190 #ifdef USE_IMAGE
191 	if (displayImage)
192 	    initImage();
193 #endif
194     }
195     fmInitialized = TRUE;
196 }
197 
198 /*
199  * Display some lines.
200  */
201 static Line *cline = NULL;
202 static int ccolumn = -1;
203 
204 static int ulmode = 0, somode = 0, bomode = 0;
205 static int anch_mode = 0, emph_mode = 0, imag_mode = 0, form_mode = 0,
206     active_mode = 0, visited_mode = 0, mark_mode = 0, graph_mode = 0;
207 #ifdef USE_ANSI_COLOR
208 static Linecolor color_mode = 0;
209 #endif
210 
211 #ifdef USE_BUFINFO
212 static Buffer *save_current_buf = NULL;
213 #endif
214 
215 static char *delayed_msg = NULL;
216 
217 static void drawAnchorCursor(Buffer *buf);
218 #define redrawBuffer(buf) redrawNLine(buf, LASTLINE)
219 static void redrawNLine(Buffer *buf, int n);
220 static Line *redrawLine(Buffer *buf, Line *l, int i);
221 #ifdef USE_IMAGE
222 static int image_touch = 0;
223 static int draw_image_flag = FALSE;
224 static Line *redrawLineImage(Buffer *buf, Line *l, int i);
225 #endif
226 static int redrawLineRegion(Buffer *buf, Line *l, int i, int bpos, int epos);
227 static void do_effects(Lineprop m);
228 #ifdef USE_ANSI_COLOR
229 static void do_color(Linecolor c);
230 #endif
231 
232 static Str
make_lastline_link(Buffer * buf,char * title,char * url)233 make_lastline_link(Buffer *buf, char *title, char *url)
234 {
235     Str s = NULL, u;
236 #ifdef USE_M17N
237     Lineprop *pr;
238 #endif
239     ParsedURL pu;
240     char *p;
241     int l = COLS - 1, i;
242 
243     if (title && *title) {
244 	s = Strnew_m_charp("[", title, "]", NULL);
245 	for (p = s->ptr; *p; p++) {
246 	    if (IS_CNTRL(*p) || IS_SPACE(*p))
247 		*p = ' ';
248 	}
249 	if (url)
250 	    Strcat_charp(s, " ");
251 	l -= get_Str_strwidth(s);
252 	if (l <= 0)
253 	    return s;
254     }
255     if (!url)
256 	return s;
257     parseURL2(url, &pu, baseURL(buf));
258     u = parsedURL2Str(&pu);
259     if (DecodeURL)
260 	u = Strnew_charp(url_decode2(u->ptr, buf));
261 #ifdef USE_M17N
262     u = checkType(u, &pr, NULL);
263 #endif
264     if (l <= 4 || l >= get_Str_strwidth(u)) {
265 	if (!s)
266 	    return u;
267 	Strcat(s, u);
268 	return s;
269     }
270     if (!s)
271 	s = Strnew_size(COLS);
272     i = (l - 2) / 2;
273 #ifdef USE_M17N
274     while (i && pr[i] & PC_WCHAR2)
275 	i--;
276 #endif
277     Strcat_charp_n(s, u->ptr, i);
278     Strcat_charp(s, "..");
279     i = get_Str_strwidth(u) - (COLS - 1 - get_Str_strwidth(s));
280 #ifdef USE_M17N
281     while (i < u->length && pr[i] & PC_WCHAR2)
282 	i++;
283 #endif
284     Strcat_charp(s, &u->ptr[i]);
285     return s;
286 }
287 
288 static Str
make_lastline_message(Buffer * buf)289 make_lastline_message(Buffer *buf)
290 {
291     Str msg, s = NULL;
292     int sl = 0;
293 
294     if (displayLink) {
295 #ifdef USE_IMAGE
296 	MapArea *a = retrieveCurrentMapArea(buf);
297 	if (a)
298 	    s = make_lastline_link(buf, a->alt, a->url);
299 	else
300 #endif
301 	{
302 	    Anchor *a = retrieveCurrentAnchor(buf);
303 	    char *p = NULL;
304 	    if (a && a->title && *a->title)
305 		p = a->title;
306 	    else {
307 		Anchor *a_img = retrieveCurrentImg(buf);
308 		if (a_img && a_img->title && *a_img->title)
309 		    p = a_img->title;
310 	    }
311 	    if (p || a)
312 		s = make_lastline_link(buf, p, a ? a->url : NULL);
313 	}
314 	if (s) {
315 	    sl = get_Str_strwidth(s);
316 	    if (sl >= COLS - 3)
317 		return s;
318 	}
319     }
320 
321 #ifdef USE_MOUSE
322     if (use_mouse && mouse_action.lastline_str)
323 	msg = Strnew_charp(mouse_action.lastline_str);
324     else
325 #endif				/* not USE_MOUSE */
326 	msg = Strnew();
327     if (displayLineInfo && buf->currentLine != NULL && buf->lastLine != NULL) {
328 	int cl = buf->currentLine->real_linenumber;
329 	int ll = buf->lastLine->real_linenumber;
330 	int r = (int)((double)cl * 100.0 / (double)(ll ? ll : 1) + 0.5);
331 	Strcat(msg, Sprintf("%d/%d (%d%%)", cl, ll, r));
332     }
333     else
334 	/* FIXME: gettextize? */
335 	Strcat_charp(msg, "Viewing");
336 #ifdef USE_SSL
337     if (buf->ssl_certificate)
338 	Strcat_charp(msg, "[SSL]");
339 #endif
340     Strcat_charp(msg, " <");
341     Strcat_charp(msg, buf->buffername);
342 
343     if (s) {
344 	int l = COLS - 3 - sl;
345 	if (get_Str_strwidth(msg) > l) {
346 #ifdef USE_M17N
347 	    char *p;
348 	    for (p = msg->ptr; *p; p += get_mclen(p)) {
349 		l -= get_mcwidth(p);
350 		if (l < 0)
351 		    break;
352 	    }
353 	    l = p - msg->ptr;
354 #endif
355 	    Strtruncate(msg, l);
356 	}
357 	Strcat_charp(msg, "> ");
358 	Strcat(msg, s);
359     }
360     else {
361 	Strcat_charp(msg, ">");
362     }
363     return msg;
364 }
365 
366 void
displayBuffer(Buffer * buf,int mode)367 displayBuffer(Buffer *buf, int mode)
368 {
369     Str msg;
370     int ny = 0;
371 
372     if (!buf)
373 	return;
374     if (buf->topLine == NULL && readBufferCache(buf) == 0) {	/* clear_buffer */
375 	mode = B_FORCE_REDRAW;
376     }
377 
378     if (buf->width == 0)
379 	buf->width = INIT_BUFFER_WIDTH;
380     if (buf->height == 0)
381 	buf->height = LASTLINE + 1;
382     if ((buf->width != INIT_BUFFER_WIDTH &&
383 	 (is_html_type(buf->type) || FoldLine))
384 	|| buf->need_reshape) {
385 	buf->need_reshape = TRUE;
386 	reshapeBuffer(buf);
387     }
388     if (showLineNum) {
389 	if (buf->lastLine && buf->lastLine->real_linenumber > 0)
390 	    buf->rootX = (int)(log(buf->lastLine->real_linenumber + 0.1)
391 			       / log(10)) + 2;
392 	if (buf->rootX < 5)
393 	    buf->rootX = 5;
394 	if (buf->rootX > COLS)
395 	    buf->rootX = COLS;
396     }
397     else
398 	buf->rootX = 0;
399     buf->COLS = COLS - buf->rootX;
400     if (nTab > 1
401 #ifdef USE_MOUSE
402 	|| mouse_action.menu_str
403 #endif
404 	) {
405 	if (mode == B_FORCE_REDRAW || mode == B_REDRAW_IMAGE)
406 	    calcTabPos();
407 	ny = LastTab->y + 2;
408 	if (ny > LASTLINE)
409 	    ny = LASTLINE;
410     }
411     if (buf->rootY != ny || buf->LINES != LASTLINE - ny) {
412 	buf->rootY = ny;
413 	buf->LINES = LASTLINE - ny;
414 	arrangeCursor(buf);
415 	mode = B_REDRAW_IMAGE;
416     }
417     if (mode == B_FORCE_REDRAW || mode == B_SCROLL || mode == B_REDRAW_IMAGE ||
418 	cline != buf->topLine || ccolumn != buf->currentColumn) {
419 #ifdef USE_RAW_SCROLL
420 	if (
421 #ifdef USE_IMAGE
422 	       !(activeImage && displayImage && draw_image_flag) &&
423 #endif
424 	       mode == B_SCROLL && cline && buf->currentColumn == ccolumn) {
425 	    int n = buf->topLine->linenumber - cline->linenumber;
426 	    if (n > 0 && n < buf->LINES) {
427 		move(LASTLINE, 0);
428 		clrtoeolx();
429 		refresh();
430 		scroll(n);
431 	    }
432 	    else if (n < 0 && n > -buf->LINES) {
433 #if 0 /* defined(__CYGWIN__) */
434 		move(LASTLINE + n + 1, 0);
435 		clrtoeolx();
436 		refresh();
437 #endif				/* defined(__CYGWIN__) */
438 		rscroll(-n);
439 	    }
440 	    redrawNLine(buf, n);
441 	}
442 	else
443 #endif
444 	{
445 #ifdef USE_IMAGE
446 	    if (activeImage &&
447 		(mode == B_REDRAW_IMAGE ||
448 		 cline != buf->topLine || ccolumn != buf->currentColumn)) {
449 		if (draw_image_flag)
450 		    clear();
451 		clearImage();
452 		loadImage(buf, IMG_FLAG_STOP);
453 		image_touch++;
454 		draw_image_flag = FALSE;
455 	    }
456 #endif
457 	    redrawBuffer(buf);
458 	}
459 	cline = buf->topLine;
460 	ccolumn = buf->currentColumn;
461     }
462     if (buf->topLine == NULL)
463 	buf->topLine = buf->firstLine;
464 
465 #ifdef USE_IMAGE
466     if (buf->need_reshape) {
467 	displayBuffer(buf, B_FORCE_REDRAW);
468 	return;
469     }
470 #endif
471 
472     drawAnchorCursor(buf);
473 
474     msg = make_lastline_message(buf);
475     if (buf->firstLine == NULL) {
476 	/* FIXME: gettextize? */
477 	Strcat_charp(msg, "\tNo Line");
478     }
479     if (delayed_msg != NULL) {
480 	disp_message(delayed_msg, FALSE);
481 	delayed_msg = NULL;
482 	refresh();
483     }
484     standout();
485     message(msg->ptr, buf->cursorX + buf->rootX, buf->cursorY + buf->rootY);
486     standend();
487     term_title(conv_to_system(buf->buffername));
488     refresh();
489 #ifdef USE_IMAGE
490     if (activeImage && displayImage && buf->img && buf->image_loaded) {
491 	drawImage();
492     }
493 #endif
494 #ifdef USE_BUFINFO
495     if (buf != save_current_buf) {
496 	saveBufferInfo();
497 	save_current_buf = buf;
498     }
499 #endif
500     if (mode == B_FORCE_REDRAW &&  (buf->check_url & CHK_URL) ) {
501 	chkURLBuffer(buf);
502 	displayBuffer(buf, B_NORMAL);
503     }
504 }
505 
506 static void
drawAnchorCursor0(Buffer * buf,AnchorList * al,int hseq,int prevhseq,int tline,int eline,int active)507 drawAnchorCursor0(Buffer *buf, AnchorList *al, int hseq, int prevhseq,
508 		  int tline, int eline, int active)
509 {
510     int i, j;
511     Line *l;
512     Anchor *an;
513 
514     l = buf->topLine;
515     for (j = 0; j < al->nanchor; j++) {
516 	an = &al->anchors[j];
517 	if (an->start.line < tline)
518 	    continue;
519 	if (an->start.line >= eline)
520 	    return;
521 	for (;; l = l->next) {
522 	    if (l == NULL)
523 		return;
524 	    if (l->linenumber == an->start.line)
525 		break;
526 	}
527 	if (hseq >= 0 && an->hseq == hseq) {
528 	    int start_pos = an->start.pos;
529 	    int end_pos = an->end.pos;
530 	    for (i = an->start.pos; i < an->end.pos; i++) {
531 	        if (enable_inline_image && (l->propBuf[i] & PE_IMAGE)) {
532 		    if (start_pos == i)
533 			start_pos = i + 1;
534 		    else if (end_pos == an->end.pos)
535 		        end_pos = i - 1;
536 		}
537 		if (l->propBuf[i] & (PE_IMAGE | PE_ANCHOR | PE_FORM)) {
538 		    if (active)
539 			l->propBuf[i] |= PE_ACTIVE;
540 		    else
541 			l->propBuf[i] &= ~PE_ACTIVE;
542 		}
543 	    }
544 	    if (active && start_pos < end_pos)
545 		redrawLineRegion(buf, l, l->linenumber - tline + buf->rootY,
546 				 start_pos, end_pos);
547 	}
548 	else if (prevhseq >= 0 && an->hseq == prevhseq) {
549 	    if (active)
550 		redrawLineRegion(buf, l, l->linenumber - tline + buf->rootY,
551 				 an->start.pos, an->end.pos);
552 	}
553     }
554 }
555 
556 static void
drawAnchorCursor(Buffer * buf)557 drawAnchorCursor(Buffer *buf)
558 {
559     Anchor *an;
560     int hseq, prevhseq;
561     int tline, eline;
562 
563     if (!buf->firstLine || !buf->hmarklist)
564 	return;
565     if (!buf->href && !buf->formitem)
566 	return;
567 
568     an = retrieveCurrentAnchor(buf);
569     if (!an)
570 	an = retrieveCurrentMap(buf);
571     if (an)
572 	hseq = an->hseq;
573     else
574 	hseq = -1;
575     tline = buf->topLine->linenumber;
576     eline = tline + buf->LINES;
577     prevhseq = buf->hmarklist->prevhseq;
578 
579     if (buf->href) {
580 	drawAnchorCursor0(buf, buf->href, hseq, prevhseq, tline, eline, 1);
581 	drawAnchorCursor0(buf, buf->href, hseq, -1, tline, eline, 0);
582     }
583     if (buf->formitem) {
584 	drawAnchorCursor0(buf, buf->formitem, hseq, prevhseq, tline, eline, 1);
585 	drawAnchorCursor0(buf, buf->formitem, hseq, -1, tline, eline, 0);
586     }
587     buf->hmarklist->prevhseq = hseq;
588 }
589 
590 static void
redrawNLine(Buffer * buf,int n)591 redrawNLine(Buffer *buf, int n)
592 {
593     Line *l;
594     int i;
595 
596 #ifdef USE_COLOR
597     if (useColor) {
598 	EFFECT_ANCHOR_END_C;
599 #ifdef USE_BG_COLOR
600 	setbcolor(bg_color);
601 #endif				/* USE_BG_COLOR */
602     }
603 #endif				/* USE_COLOR */
604     if (nTab > 1
605 #ifdef USE_MOUSE
606 	|| mouse_action.menu_str
607 #endif
608 	) {
609 	TabBuffer *t;
610 	int l;
611 
612 	move(0, 0);
613 #ifdef USE_MOUSE
614 	if (mouse_action.menu_str)
615 	    addstr(mouse_action.menu_str);
616 #endif
617 	clrtoeolx();
618 	for (t = FirstTab; t; t = t->nextTab) {
619 	    move(t->y, t->x1);
620 	    if (t == CurrentTab)
621 		bold();
622 	    addch('[');
623 	    l = t->x2 - t->x1 - 1 - get_strwidth(t->currentBuffer->buffername);
624 	    if (l < 0)
625 		l = 0;
626 	    if (l / 2 > 0)
627 		addnstr_sup(" ", l / 2);
628 	    if (t == CurrentTab)
629 		EFFECT_ACTIVE_START;
630 	    addnstr(t->currentBuffer->buffername, t->x2 - t->x1 - l);
631 	    if (t == CurrentTab)
632 		EFFECT_ACTIVE_END;
633 	    if ((l + 1) / 2 > 0)
634 		addnstr_sup(" ", (l + 1) / 2);
635 	    move(t->y, t->x2);
636 	    addch(']');
637 	    if (t == CurrentTab)
638 		boldend();
639 	}
640 #if 0
641 	move(0, COLS - 2);
642 	addstr(" x");
643 #endif
644 	move(LastTab->y + 1, 0);
645 	for (i = 0; i < COLS; i++)
646 	    addch('~');
647     }
648     for (i = 0, l = buf->topLine; i < buf->LINES; i++, l = l->next) {
649 	if (i >= buf->LINES - n || i < -n)
650 	    l = redrawLine(buf, l, i + buf->rootY);
651 	if (l == NULL)
652 	    break;
653     }
654     if (n > 0) {
655 	move(i + buf->rootY, 0);
656 	clrtobotx();
657     }
658 
659 #ifdef USE_IMAGE
660     if (!(activeImage && displayImage && buf->img))
661 	return;
662     move(buf->cursorY + buf->rootY, buf->cursorX + buf->rootX);
663     for (i = 0, l = buf->topLine; i < buf->LINES && l; i++, l = l->next) {
664 	if (i >= buf->LINES - n || i < -n)
665 	    redrawLineImage(buf, l, i + buf->rootY);
666     }
667     getAllImage(buf);
668 #endif
669 }
670 
671 static Line *
redrawLine(Buffer * buf,Line * l,int i)672 redrawLine(Buffer *buf, Line *l, int i)
673 {
674     int j, pos, rcol, ncol, delta = 1;
675     int column = buf->currentColumn;
676     char *p;
677     Lineprop *pr;
678 #ifdef USE_ANSI_COLOR
679     Linecolor *pc;
680 #endif
681 #ifdef USE_COLOR
682     Anchor *a;
683     ParsedURL url;
684     int k, vpos = -1;
685 #endif
686 
687     if (l == NULL) {
688 	if (buf->pagerSource) {
689 	    l = getNextPage(buf, buf->LINES + buf->rootY - i);
690 	    if (l == NULL)
691 		return NULL;
692 	}
693 	else
694 	    return NULL;
695     }
696     move(i, 0);
697     if (showLineNum) {
698 	char tmp[16];
699 	if (!buf->rootX) {
700 	    if (buf->lastLine->real_linenumber > 0)
701 		buf->rootX = (int)(log(buf->lastLine->real_linenumber + 0.1)
702 				   / log(10)) + 2;
703 	    if (buf->rootX < 5)
704 		buf->rootX = 5;
705 	    if (buf->rootX > COLS)
706 		buf->rootX = COLS;
707 	    buf->COLS = COLS - buf->rootX;
708 	}
709 	if (l->real_linenumber && !l->bpos)
710 	    sprintf(tmp, "%*ld:", buf->rootX - 1, l->real_linenumber);
711 	else
712 	    sprintf(tmp, "%*s ", buf->rootX - 1, "");
713 	addstr(tmp);
714     }
715     move(i, buf->rootX);
716     if (l->width < 0)
717 	l->width = COLPOS(l, l->len);
718     if (l->len == 0 || l->width - 1 < column) {
719 	clrtoeolx();
720 	return l;
721     }
722     /* need_clrtoeol(); */
723     pos = columnPos(l, column);
724     p = &(l->lineBuf[pos]);
725     pr = &(l->propBuf[pos]);
726 #ifdef USE_ANSI_COLOR
727     if (useColor && l->colorBuf)
728 	pc = &(l->colorBuf[pos]);
729     else
730 	pc = NULL;
731 #endif
732     rcol = COLPOS(l, pos);
733 
734     for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j += delta) {
735 #ifdef USE_COLOR
736 	if (useVisitedColor && vpos <= pos + j && !(pr[j] & PE_VISITED)) {
737 	    a = retrieveAnchor(buf->href, l->linenumber, pos + j);
738 	    if (a) {
739 		parseURL2(a->url, &url, baseURL(buf));
740 		if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
741 		    for (k = a->start.pos; k < a->end.pos; k++)
742 			pr[k - pos] |= PE_VISITED;
743 		}
744 		vpos = a->end.pos;
745 	    }
746 	}
747 #endif
748 #ifdef USE_M17N
749 	delta = wtf_len((wc_uchar *) & p[j]);
750 #endif
751 	ncol = COLPOS(l, pos + j + delta);
752 	if (ncol - column > buf->COLS)
753 	    break;
754 #ifdef USE_ANSI_COLOR
755 	if (pc)
756 	    do_color(pc[j]);
757 #endif
758 	if (rcol < column) {
759 	    for (rcol = column; rcol < ncol; rcol++)
760 		addChar(' ', 0);
761 	    continue;
762 	}
763 	if (p[j] == '\t') {
764 	    for (; rcol < ncol; rcol++)
765 		addChar(' ', 0);
766 	}
767 	else {
768 #ifdef USE_M17N
769 	    addMChar(&p[j], pr[j], delta);
770 #else
771 	    addChar(p[j], pr[j]);
772 #endif
773 	}
774 	rcol = ncol;
775     }
776     if (somode) {
777 	somode = FALSE;
778 	standend();
779     }
780     if (ulmode) {
781 	ulmode = FALSE;
782 	underlineend();
783     }
784     if (bomode) {
785 	bomode = FALSE;
786 	boldend();
787     }
788     if (emph_mode) {
789 	emph_mode = FALSE;
790 	boldend();
791     }
792 
793     if (anch_mode) {
794 	anch_mode = FALSE;
795 	EFFECT_ANCHOR_END;
796     }
797     if (imag_mode) {
798 	imag_mode = FALSE;
799 	EFFECT_IMAGE_END;
800     }
801     if (form_mode) {
802 	form_mode = FALSE;
803 	EFFECT_FORM_END;
804     }
805     if (visited_mode) {
806 	visited_mode = FALSE;
807 	EFFECT_VISITED_END;
808     }
809     if (active_mode) {
810 	active_mode = FALSE;
811 	EFFECT_ACTIVE_END;
812     }
813     if (mark_mode) {
814 	mark_mode = FALSE;
815 	EFFECT_MARK_END;
816     }
817     if (graph_mode) {
818 	graph_mode = FALSE;
819 	graphend();
820     }
821 #ifdef USE_ANSI_COLOR
822     if (color_mode)
823 	do_color(0);
824 #endif
825     if (rcol - column < buf->COLS)
826 	clrtoeolx();
827     return l;
828 }
829 
830 #ifdef USE_IMAGE
831 static Line *
redrawLineImage(Buffer * buf,Line * l,int i)832 redrawLineImage(Buffer *buf, Line *l, int i)
833 {
834     int j, pos, rcol;
835     int column = buf->currentColumn;
836     Anchor *a;
837     int x, y, sx, sy, w, h;
838 
839     if (l == NULL)
840 	return NULL;
841     if (l->width < 0)
842 	l->width = COLPOS(l, l->len);
843     if (l->len == 0 || l->width - 1 < column)
844 	return l;
845     pos = columnPos(l, column);
846     rcol = COLPOS(l, pos);
847     for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j++) {
848 	if (rcol - column < 0) {
849 	    rcol = COLPOS(l, pos + j + 1);
850 	    continue;
851 	}
852 	a = retrieveAnchor(buf->img, l->linenumber, pos + j);
853 	if (a && a->image && a->image->touch < image_touch) {
854 	    Image *image = a->image;
855 	    ImageCache *cache;
856 
857 	    cache = image->cache = getImage(image, baseURL(buf),
858 					    buf->image_flag);
859 	    if (cache) {
860 		if ((image->width < 0 && cache->width > 0) ||
861 		    (image->height < 0 && cache->height > 0)) {
862 		    image->width = cache->width;
863 		    image->height = cache->height;
864 		    buf->need_reshape = TRUE;
865 		}
866 		x = (int)((rcol - column + buf->rootX) * pixel_per_char);
867 		y = (int)(i * pixel_per_line);
868 		sx = (int)((rcol - COLPOS(l, a->start.pos)) * pixel_per_char);
869 		sy = (int)((l->linenumber - image->y) * pixel_per_line);
870 		if (! enable_inline_image) {
871 		    if (sx == 0 && x + image->xoffset >= 0)
872 			x += image->xoffset;
873 		    else
874 			sx -= image->xoffset;
875 		    if (sy == 0 && y + image->yoffset >= 0)
876 			y += image->yoffset;
877 		    else
878 			sy -= image->yoffset;
879 		}
880 		if (image->width > 0)
881 		    w = image->width - sx;
882 		else
883 		    w = (int)(8 * pixel_per_char - sx);
884 		if (image->height > 0)
885 		    h = image->height - sy;
886 		else
887 		    h = (int)(pixel_per_line - sy);
888 		if (w > (int)((buf->rootX + buf->COLS) * pixel_per_char - x))
889 		    w = (int)((buf->rootX + buf->COLS) * pixel_per_char - x);
890 		if (h > (int)(LASTLINE * pixel_per_line - y))
891 		    h = (int)(LASTLINE * pixel_per_line - y);
892 		addImage(cache, x, y, sx, sy, w, h);
893 		image->touch = image_touch;
894 		draw_image_flag = TRUE;
895 	    }
896 	}
897 	rcol = COLPOS(l, pos + j + 1);
898     }
899     return l;
900 }
901 #endif
902 
903 static int
redrawLineRegion(Buffer * buf,Line * l,int i,int bpos,int epos)904 redrawLineRegion(Buffer *buf, Line *l, int i, int bpos, int epos)
905 {
906     int j, pos, rcol, ncol, delta = 1;
907     int column = buf->currentColumn;
908     char *p;
909     Lineprop *pr;
910 #ifdef USE_ANSI_COLOR
911     Linecolor *pc;
912 #endif
913     int bcol, ecol;
914 #ifdef USE_COLOR
915     Anchor *a;
916     ParsedURL url;
917     int k, vpos = -1;
918 #endif
919 
920     if (l == NULL)
921 	return 0;
922     pos = columnPos(l, column);
923     p = &(l->lineBuf[pos]);
924     pr = &(l->propBuf[pos]);
925 #ifdef USE_ANSI_COLOR
926     if (useColor && l->colorBuf)
927 	pc = &(l->colorBuf[pos]);
928     else
929 	pc = NULL;
930 #endif
931     rcol = COLPOS(l, pos);
932     bcol = bpos - pos;
933     ecol = epos - pos;
934 
935     for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j += delta) {
936 #ifdef USE_COLOR
937 	if (useVisitedColor && vpos <= pos + j && !(pr[j] & PE_VISITED)) {
938 	    a = retrieveAnchor(buf->href, l->linenumber, pos + j);
939 	    if (a) {
940 		parseURL2(a->url, &url, baseURL(buf));
941 		if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
942 		    for (k = a->start.pos; k < a->end.pos; k++)
943 			pr[k - pos] |= PE_VISITED;
944 		}
945 		vpos = a->end.pos;
946 	    }
947 	}
948 #endif
949 #ifdef USE_M17N
950 	delta = wtf_len((wc_uchar *) & p[j]);
951 #endif
952 	ncol = COLPOS(l, pos + j + delta);
953 	if (ncol - column > buf->COLS)
954 	    break;
955 #ifdef USE_ANSI_COLOR
956 	if (pc)
957 	    do_color(pc[j]);
958 #endif
959 	if (j >= bcol && j < ecol) {
960 	    if (rcol < column) {
961 		move(i, buf->rootX);
962 		for (rcol = column; rcol < ncol; rcol++)
963 		    addChar(' ', 0);
964 		continue;
965 	    }
966 	    move(i, rcol - column + buf->rootX);
967 	    if (p[j] == '\t') {
968 		for (; rcol < ncol; rcol++)
969 		    addChar(' ', 0);
970 	    }
971 	    else
972 #ifdef USE_M17N
973 		addMChar(&p[j], pr[j], delta);
974 #else
975 		addChar(p[j], pr[j]);
976 #endif
977 	}
978 	rcol = ncol;
979     }
980     if (somode) {
981 	somode = FALSE;
982 	standend();
983     }
984     if (ulmode) {
985 	ulmode = FALSE;
986 	underlineend();
987     }
988     if (bomode) {
989 	bomode = FALSE;
990 	boldend();
991     }
992     if (emph_mode) {
993 	emph_mode = FALSE;
994 	boldend();
995     }
996 
997     if (anch_mode) {
998 	anch_mode = FALSE;
999 	EFFECT_ANCHOR_END;
1000     }
1001     if (imag_mode) {
1002 	imag_mode = FALSE;
1003 	EFFECT_IMAGE_END;
1004     }
1005     if (form_mode) {
1006 	form_mode = FALSE;
1007 	EFFECT_FORM_END;
1008     }
1009     if (visited_mode) {
1010 	visited_mode = FALSE;
1011 	EFFECT_VISITED_END;
1012     }
1013     if (active_mode) {
1014 	active_mode = FALSE;
1015 	EFFECT_ACTIVE_END;
1016     }
1017     if (mark_mode) {
1018 	mark_mode = FALSE;
1019 	EFFECT_MARK_END;
1020     }
1021     if (graph_mode) {
1022 	graph_mode = FALSE;
1023 	graphend();
1024     }
1025 #ifdef USE_ANSI_COLOR
1026     if (color_mode)
1027 	do_color(0);
1028 #endif
1029     return rcol - column;
1030 }
1031 
1032 #define do_effect1(effect,modeflag,action_start,action_end) \
1033 if (m & effect) { \
1034     if (!modeflag) { \
1035 	action_start; \
1036 	modeflag = TRUE; \
1037     } \
1038 }
1039 
1040 #define do_effect2(effect,modeflag,action_start,action_end) \
1041 if (modeflag) { \
1042     action_end; \
1043     modeflag = FALSE; \
1044 }
1045 
1046 static void
do_effects(Lineprop m)1047 do_effects(Lineprop m)
1048 {
1049     /* effect end */
1050     do_effect2(PE_UNDER, ulmode, underline(), underlineend());
1051     do_effect2(PE_STAND, somode, standout(), standend());
1052     do_effect2(PE_BOLD, bomode, bold(), boldend());
1053     do_effect2(PE_EMPH, emph_mode, bold(), boldend());
1054     do_effect2(PE_ANCHOR, anch_mode, EFFECT_ANCHOR_START, EFFECT_ANCHOR_END);
1055     do_effect2(PE_IMAGE, imag_mode, EFFECT_IMAGE_START, EFFECT_IMAGE_END);
1056     do_effect2(PE_FORM, form_mode, EFFECT_FORM_START, EFFECT_FORM_END);
1057     do_effect2(PE_VISITED, visited_mode, EFFECT_VISITED_START,
1058 	       EFFECT_VISITED_END);
1059     do_effect2(PE_ACTIVE, active_mode, EFFECT_ACTIVE_START, EFFECT_ACTIVE_END);
1060     do_effect2(PE_MARK, mark_mode, EFFECT_MARK_START, EFFECT_MARK_END);
1061     if (graph_mode) {
1062 	graphend();
1063 	graph_mode = FALSE;
1064     }
1065 
1066     /* effect start */
1067     do_effect1(PE_UNDER, ulmode, underline(), underlineend());
1068     do_effect1(PE_STAND, somode, standout(), standend());
1069     do_effect1(PE_BOLD, bomode, bold(), boldend());
1070     do_effect1(PE_EMPH, emph_mode, bold(), boldend());
1071     do_effect1(PE_ANCHOR, anch_mode, EFFECT_ANCHOR_START, EFFECT_ANCHOR_END);
1072     do_effect1(PE_IMAGE, imag_mode, EFFECT_IMAGE_START, EFFECT_IMAGE_END);
1073     do_effect1(PE_FORM, form_mode, EFFECT_FORM_START, EFFECT_FORM_END);
1074     do_effect1(PE_VISITED, visited_mode, EFFECT_VISITED_START,
1075 	       EFFECT_VISITED_END);
1076     do_effect1(PE_ACTIVE, active_mode, EFFECT_ACTIVE_START, EFFECT_ACTIVE_END);
1077     do_effect1(PE_MARK, mark_mode, EFFECT_MARK_START, EFFECT_MARK_END);
1078 }
1079 
1080 #ifdef USE_ANSI_COLOR
1081 static void
do_color(Linecolor c)1082 do_color(Linecolor c)
1083 {
1084     if (c & 0x8)
1085 	setfcolor(c & 0x7);
1086     else if (color_mode & 0x8)
1087 	setfcolor(basic_color);
1088 #ifdef USE_BG_COLOR
1089     if (c & 0x80)
1090 	setbcolor((c >> 4) & 0x7);
1091     else if (color_mode & 0x80)
1092 	setbcolor(bg_color);
1093 #endif
1094     color_mode = c;
1095 }
1096 #endif
1097 
1098 #ifdef USE_M17N
1099 void
addChar(char c,Lineprop mode)1100 addChar(char c, Lineprop mode)
1101 {
1102     addMChar(&c, mode, 1);
1103 }
1104 
1105 void
addMChar(char * p,Lineprop mode,size_t len)1106 addMChar(char *p, Lineprop mode, size_t len)
1107 #else
1108 void
1109 addChar(char c, Lineprop mode)
1110 #endif
1111 {
1112     Lineprop m = CharEffect(mode);
1113 #ifdef USE_M17N
1114     char c = *p;
1115 
1116     if (mode & PC_WCHAR2)
1117 	return;
1118 #endif
1119     do_effects(m);
1120     if (mode & PC_SYMBOL) {
1121 	char **symbol;
1122 #ifdef USE_M17N
1123 	int w = (mode & PC_KANJI) ? 2 : 1;
1124 
1125 	c = ((char)wtf_get_code((wc_uchar *) p) & 0x7f) - SYMBOL_BASE;
1126 #else
1127 	c -= SYMBOL_BASE;
1128 #endif
1129 	if (graph_ok() && c < N_GRAPH_SYMBOL) {
1130 	    if (!graph_mode) {
1131 		graphstart();
1132 		graph_mode = TRUE;
1133 	    }
1134 #ifdef USE_M17N
1135 	    if (w == 2 && WcOption.use_wide)
1136 		addstr(graph2_symbol[(unsigned char)c % N_GRAPH_SYMBOL]);
1137 	    else
1138 #endif
1139 		addch(*graph_symbol[(unsigned char)c % N_GRAPH_SYMBOL]);
1140 	}
1141 	else {
1142 #ifdef USE_M17N
1143 	    symbol = get_symbol(DisplayCharset, &w);
1144 	    addstr(symbol[(unsigned char)c % N_SYMBOL]);
1145 #else
1146 	    symbol = get_symbol();
1147 	    addch(*symbol[(unsigned char)c % N_SYMBOL]);
1148 #endif
1149 	}
1150     }
1151     else if (mode & PC_CTRL) {
1152 	switch (c) {
1153 	case '\t':
1154 	    addch(c);
1155 	    break;
1156 	case '\n':
1157 	    addch(' ');
1158 	    break;
1159 	case '\r':
1160 	    break;
1161 	case DEL_CODE:
1162 	    addstr("^?");
1163 	    break;
1164 	default:
1165 	    addch('^');
1166 	    addch(c + '@');
1167 	    break;
1168 	}
1169     }
1170 #ifdef USE_M17N
1171     else if (mode & PC_UNKNOWN) {
1172 	char buf[5];
1173 	sprintf(buf, "[%.2X]",
1174 		(unsigned char)wtf_get_code((wc_uchar *) p) | 0x80);
1175 	addstr(buf);
1176     }
1177     else
1178 	addmch(p, len);
1179 #else
1180     else if (0x80 <= (unsigned char)c && (unsigned char)c <= NBSP_CODE)
1181 	addch(' ');
1182     else
1183 	addch(c);
1184 #endif
1185 }
1186 
1187 static GeneralList *message_list = NULL;
1188 
1189 void
record_err_message(char * s)1190 record_err_message(char *s)
1191 {
1192     if (fmInitialized) {
1193 	if (!message_list)
1194 	    message_list = newGeneralList();
1195 	if (message_list->nitem >= LINES)
1196 	    popValue(message_list);
1197 	pushValue(message_list, allocStr(s, -1));
1198     }
1199 }
1200 
1201 /*
1202  * List of error messages
1203  */
1204 Buffer *
message_list_panel(void)1205 message_list_panel(void)
1206 {
1207     Str tmp = Strnew_size(LINES * COLS);
1208     ListItem *p;
1209 
1210     /* FIXME: gettextize? */
1211     Strcat_charp(tmp,
1212 		 "<html><head><title>List of error messages</title></head><body>"
1213 		 "<h1>List of error messages</h1><table cellpadding=0>\n");
1214     if (message_list)
1215 	for (p = message_list->last; p; p = p->prev)
1216 	    Strcat_m_charp(tmp, "<tr><td><pre>", html_quote(p->ptr),
1217 			   "</pre></td></tr>\n", NULL);
1218     else
1219 	Strcat_charp(tmp, "<tr><td>(no message recorded)</td></tr>\n");
1220     Strcat_charp(tmp, "</table></body></html>");
1221     return loadHTMLString(tmp);
1222 }
1223 
1224 void
message(char * s,int return_x,int return_y)1225 message(char *s, int return_x, int return_y)
1226 {
1227     if (!fmInitialized)
1228 	return;
1229     move(LASTLINE, 0);
1230     addnstr(s, COLS - 1);
1231     clrtoeolx();
1232     move(return_y, return_x);
1233 }
1234 
1235 void
disp_err_message(char * s,int redraw_current)1236 disp_err_message(char *s, int redraw_current)
1237 {
1238     record_err_message(s);
1239     disp_message(s, redraw_current);
1240 }
1241 
1242 void
disp_message_nsec(char * s,int redraw_current,int sec,int purge,int mouse)1243 disp_message_nsec(char *s, int redraw_current, int sec, int purge, int mouse)
1244 {
1245     if (QuietMessage)
1246 	return;
1247     if (!fmInitialized) {
1248 	fprintf(stderr, "%s\n", conv_to_system(s));
1249 	return;
1250     }
1251     if (CurrentTab != NULL && Currentbuf != NULL)
1252 	message(s, Currentbuf->cursorX + Currentbuf->rootX,
1253 		Currentbuf->cursorY + Currentbuf->rootY);
1254     else
1255 	message(s, LASTLINE, 0);
1256     refresh();
1257 #ifdef USE_MOUSE
1258     if (mouse && use_mouse)
1259 	mouse_active();
1260 #endif
1261     sleep_till_anykey(sec, purge);
1262 #ifdef USE_MOUSE
1263     if (mouse && use_mouse)
1264 	mouse_inactive();
1265 #endif
1266     if (CurrentTab != NULL && Currentbuf != NULL && redraw_current)
1267 	displayBuffer(Currentbuf, B_NORMAL);
1268 }
1269 
1270 void
disp_message(char * s,int redraw_current)1271 disp_message(char *s, int redraw_current)
1272 {
1273     disp_message_nsec(s, redraw_current, 10, FALSE, TRUE);
1274 }
1275 #ifdef USE_MOUSE
1276 void
disp_message_nomouse(char * s,int redraw_current)1277 disp_message_nomouse(char *s, int redraw_current)
1278 {
1279     disp_message_nsec(s, redraw_current, 10, FALSE, FALSE);
1280 }
1281 #endif
1282 
1283 void
set_delayed_message(char * s)1284 set_delayed_message(char *s)
1285 {
1286     delayed_msg = allocStr(s, -1);
1287 }
1288 
1289 void
cursorUp0(Buffer * buf,int n)1290 cursorUp0(Buffer *buf, int n)
1291 {
1292     if (buf->cursorY > 0)
1293 	cursorUpDown(buf, -1);
1294     else {
1295 	buf->topLine = lineSkip(buf, buf->topLine, -n, FALSE);
1296 	if (buf->currentLine->prev != NULL)
1297 	    buf->currentLine = buf->currentLine->prev;
1298 	arrangeLine(buf);
1299     }
1300 }
1301 
1302 void
cursorUp(Buffer * buf,int n)1303 cursorUp(Buffer *buf, int n)
1304 {
1305     Line *l = buf->currentLine;
1306     if (buf->firstLine == NULL)
1307 	return;
1308     while (buf->currentLine->prev && buf->currentLine->bpos)
1309 	cursorUp0(buf, n);
1310     if (buf->currentLine == buf->firstLine) {
1311 	gotoLine(buf, l->linenumber);
1312 	arrangeLine(buf);
1313 	return;
1314     }
1315     cursorUp0(buf, n);
1316     while (buf->currentLine->prev && buf->currentLine->bpos &&
1317 	   buf->currentLine->bwidth >= buf->currentColumn + buf->visualpos)
1318 	cursorUp0(buf, n);
1319 }
1320 
1321 void
cursorDown0(Buffer * buf,int n)1322 cursorDown0(Buffer *buf, int n)
1323 {
1324     if (buf->cursorY < buf->LINES - 1)
1325 	cursorUpDown(buf, 1);
1326     else {
1327 	buf->topLine = lineSkip(buf, buf->topLine, n, FALSE);
1328 	if (buf->currentLine->next != NULL)
1329 	    buf->currentLine = buf->currentLine->next;
1330 	arrangeLine(buf);
1331     }
1332 }
1333 
1334 void
cursorDown(Buffer * buf,int n)1335 cursorDown(Buffer *buf, int n)
1336 {
1337     Line *l = buf->currentLine;
1338     if (buf->firstLine == NULL)
1339 	return;
1340     while (buf->currentLine->next && buf->currentLine->next->bpos)
1341 	cursorDown0(buf, n);
1342     if (buf->currentLine == buf->lastLine) {
1343 	gotoLine(buf, l->linenumber);
1344 	arrangeLine(buf);
1345 	return;
1346     }
1347     cursorDown0(buf, n);
1348     while (buf->currentLine->next && buf->currentLine->next->bpos &&
1349 	   buf->currentLine->bwidth + buf->currentLine->width <
1350 	   buf->currentColumn + buf->visualpos)
1351 	cursorDown0(buf, n);
1352 }
1353 
1354 void
cursorUpDown(Buffer * buf,int n)1355 cursorUpDown(Buffer *buf, int n)
1356 {
1357     Line *cl = buf->currentLine;
1358 
1359     if (buf->firstLine == NULL)
1360 	return;
1361     if ((buf->currentLine = currentLineSkip(buf, cl, n, FALSE)) == cl)
1362 	return;
1363     arrangeLine(buf);
1364 }
1365 
1366 void
cursorRight(Buffer * buf,int n)1367 cursorRight(Buffer *buf, int n)
1368 {
1369     int i, delta = 1, cpos, vpos2;
1370     Line *l = buf->currentLine;
1371     Lineprop *p;
1372 
1373     if (buf->firstLine == NULL)
1374 	return;
1375     if (buf->pos == l->len && !(l->next && l->next->bpos))
1376 	return;
1377     i = buf->pos;
1378     p = l->propBuf;
1379 #ifdef USE_M17N
1380     while (i + delta < l->len && p[i + delta] & PC_WCHAR2)
1381 	delta++;
1382 #endif
1383     if (i + delta < l->len) {
1384 	buf->pos = i + delta;
1385     }
1386     else if (l->len == 0) {
1387 	buf->pos = 0;
1388     }
1389     else if (l->next && l->next->bpos) {
1390 	cursorDown0(buf, 1);
1391 	buf->pos = 0;
1392 	arrangeCursor(buf);
1393 	return;
1394     }
1395     else {
1396 	buf->pos = l->len - 1;
1397 #ifdef USE_M17N
1398 	while (buf->pos && p[buf->pos] & PC_WCHAR2)
1399 	    buf->pos--;
1400 #endif
1401     }
1402     cpos = COLPOS(l, buf->pos);
1403     buf->visualpos = l->bwidth + cpos - buf->currentColumn;
1404     delta = 1;
1405 #ifdef USE_M17N
1406     while (buf->pos + delta < l->len && p[buf->pos + delta] & PC_WCHAR2)
1407 	delta++;
1408 #endif
1409     vpos2 = COLPOS(l, buf->pos + delta) - buf->currentColumn - 1;
1410     if (vpos2 >= buf->COLS && n) {
1411 	columnSkip(buf, n + (vpos2 - buf->COLS) - (vpos2 - buf->COLS) % n);
1412 	buf->visualpos = l->bwidth + cpos - buf->currentColumn;
1413     }
1414     buf->cursorX = buf->visualpos - l->bwidth;
1415 }
1416 
1417 void
cursorLeft(Buffer * buf,int n)1418 cursorLeft(Buffer *buf, int n)
1419 {
1420     int i, delta = 1, cpos;
1421     Line *l = buf->currentLine;
1422     Lineprop *p;
1423 
1424     if (buf->firstLine == NULL)
1425 	return;
1426     i = buf->pos;
1427     p = l->propBuf;
1428 #ifdef USE_M17N
1429     while (i - delta > 0 && p[i - delta] & PC_WCHAR2)
1430 	delta++;
1431 #endif
1432     if (i >= delta)
1433 	buf->pos = i - delta;
1434     else if (l->prev && l->bpos) {
1435 	cursorUp0(buf, -1);
1436 	buf->pos = buf->currentLine->len - 1;
1437 	arrangeCursor(buf);
1438 	return;
1439     }
1440     else
1441 	buf->pos = 0;
1442     cpos = COLPOS(l, buf->pos);
1443     buf->visualpos = l->bwidth + cpos - buf->currentColumn;
1444     if (buf->visualpos - l->bwidth < 0 && n) {
1445 	columnSkip(buf,
1446 		   -n + buf->visualpos - l->bwidth - (buf->visualpos -
1447 						      l->bwidth) % n);
1448 	buf->visualpos = l->bwidth + cpos - buf->currentColumn;
1449     }
1450     buf->cursorX = buf->visualpos - l->bwidth;
1451 }
1452 
1453 void
cursorHome(Buffer * buf)1454 cursorHome(Buffer *buf)
1455 {
1456     buf->visualpos = 0;
1457     buf->cursorX = buf->cursorY = 0;
1458 }
1459 
1460 
1461 /*
1462  * Arrange line,column and cursor position according to current line and
1463  * current position.
1464  */
1465 void
arrangeCursor(Buffer * buf)1466 arrangeCursor(Buffer *buf)
1467 {
1468     int col, col2, pos;
1469     int delta = 1;
1470     if (buf == NULL || buf->currentLine == NULL)
1471 	return;
1472     /* Arrange line */
1473     if (buf->currentLine->linenumber - buf->topLine->linenumber >= buf->LINES
1474 	|| buf->currentLine->linenumber < buf->topLine->linenumber) {
1475 	/*
1476 	 * buf->topLine = buf->currentLine;
1477 	 */
1478 	buf->topLine = lineSkip(buf, buf->currentLine, 0, FALSE);
1479     }
1480     /* Arrange column */
1481     while (buf->pos < 0 && buf->currentLine->prev && buf->currentLine->bpos) {
1482 	pos = buf->pos + buf->currentLine->prev->len;
1483 	cursorUp0(buf, 1);
1484 	buf->pos = pos;
1485     }
1486     while (buf->pos >= buf->currentLine->len && buf->currentLine->next &&
1487 	   buf->currentLine->next->bpos) {
1488 	pos = buf->pos - buf->currentLine->len;
1489 	cursorDown0(buf, 1);
1490 	buf->pos = pos;
1491     }
1492     if (buf->currentLine->len == 0 || buf->pos < 0)
1493 	buf->pos = 0;
1494     else if (buf->pos >= buf->currentLine->len)
1495 	buf->pos = buf->currentLine->len - 1;
1496 #ifdef USE_M17N
1497     while (buf->pos > 0 && buf->currentLine->propBuf[buf->pos] & PC_WCHAR2)
1498 	buf->pos--;
1499 #endif
1500     col = COLPOS(buf->currentLine, buf->pos);
1501 #ifdef USE_M17N
1502     while (buf->pos + delta < buf->currentLine->len &&
1503 	   buf->currentLine->propBuf[buf->pos + delta] & PC_WCHAR2)
1504 	delta++;
1505 #endif
1506     col2 = COLPOS(buf->currentLine, buf->pos + delta);
1507     if (col < buf->currentColumn || col2 > buf->COLS + buf->currentColumn) {
1508 	buf->currentColumn = 0;
1509 	if (col2 > buf->COLS)
1510 	    columnSkip(buf, col);
1511     }
1512     /* Arrange cursor */
1513     buf->cursorY = buf->currentLine->linenumber - buf->topLine->linenumber;
1514     buf->visualpos = buf->currentLine->bwidth +
1515 	COLPOS(buf->currentLine, buf->pos) - buf->currentColumn;
1516     buf->cursorX = buf->visualpos - buf->currentLine->bwidth;
1517 #ifdef DISPLAY_DEBUG
1518     fprintf(stderr,
1519 	    "arrangeCursor: column=%d, cursorX=%d, visualpos=%d, pos=%d, len=%d\n",
1520 	    buf->currentColumn, buf->cursorX, buf->visualpos, buf->pos,
1521 	    buf->currentLine->len);
1522 #endif
1523 }
1524 
1525 void
arrangeLine(Buffer * buf)1526 arrangeLine(Buffer *buf)
1527 {
1528     int i, cpos;
1529 
1530     if (buf->firstLine == NULL)
1531 	return;
1532     buf->cursorY = buf->currentLine->linenumber - buf->topLine->linenumber;
1533     i = columnPos(buf->currentLine, buf->currentColumn + buf->visualpos
1534 		  - buf->currentLine->bwidth);
1535     cpos = COLPOS(buf->currentLine, i) - buf->currentColumn;
1536     if (cpos >= 0) {
1537 	buf->cursorX = cpos;
1538 	buf->pos = i;
1539     }
1540     else if (buf->currentLine->len > i) {
1541 	buf->cursorX = 0;
1542 	buf->pos = i + 1;
1543     }
1544     else {
1545 	buf->cursorX = 0;
1546 	buf->pos = 0;
1547     }
1548 #ifdef DISPLAY_DEBUG
1549     fprintf(stderr,
1550 	    "arrangeLine: column=%d, cursorX=%d, visualpos=%d, pos=%d, len=%d\n",
1551 	    buf->currentColumn, buf->cursorX, buf->visualpos, buf->pos,
1552 	    buf->currentLine->len);
1553 #endif
1554 }
1555 
1556 void
cursorXY(Buffer * buf,int x,int y)1557 cursorXY(Buffer *buf, int x, int y)
1558 {
1559     int oldX;
1560 
1561     cursorUpDown(buf, y - buf->cursorY);
1562 
1563     if (buf->cursorX > x) {
1564 	while (buf->cursorX > x)
1565 	    cursorLeft(buf, buf->COLS / 2);
1566     }
1567     else if (buf->cursorX < x) {
1568 	while (buf->cursorX < x) {
1569 	    oldX = buf->cursorX;
1570 
1571 	    cursorRight(buf, buf->COLS / 2);
1572 
1573 	    if (oldX == buf->cursorX)
1574 		break;
1575 	}
1576 	if (buf->cursorX > x)
1577 	    cursorLeft(buf, buf->COLS / 2);
1578     }
1579 }
1580 
1581 void
restorePosition(Buffer * buf,Buffer * orig)1582 restorePosition(Buffer *buf, Buffer *orig)
1583 {
1584     buf->topLine = lineSkip(buf, buf->firstLine, TOP_LINENUMBER(orig) - 1,
1585 			    FALSE);
1586     gotoLine(buf, CUR_LINENUMBER(orig));
1587     buf->pos = orig->pos;
1588     if (buf->currentLine && orig->currentLine)
1589 	buf->pos += orig->currentLine->bpos - buf->currentLine->bpos;
1590     buf->currentColumn = orig->currentColumn;
1591     arrangeCursor(buf);
1592 }
1593 
1594 /* Local Variables:    */
1595 /* c-basic-offset: 4   */
1596 /* tab-width: 8        */
1597 /* End:                */
1598