1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "vt_line.h"
4
5 #include <string.h> /* memset */
6 #include <pobl/bl_debug.h>
7 #include <pobl/bl_util.h> /* BL_MIN */
8 #include <pobl/bl_mem.h> /* alloca */
9
10 #include "vt_ctl_loader.h"
11 #include "vt_ot_layout.h"
12
13 #if 0
14 #define __DEBUG
15 #endif
16
17 #ifdef __DEBUG
18 #define END_CHAR_INDEX(line) \
19 ((line)->num_filled_chars == 0 && \
20 bl_debug_printf("END_CHAR_INDEX()" BL_DEBUG_TAG " num_filled_chars is 0.\n") \
21 ? 0 \
22 : (line)->num_filled_chars - 1)
23 #else
24 #define END_CHAR_INDEX(line) \
25 ((line)->num_filled_chars == 0 ? 0 : (line)->num_filled_chars - 1)
26 #endif
27
28 #define IS_EMPTY(line) ((line)->num_filled_chars == 0)
29
30 #define vt_line_is_using_bidi(line) ((line)->ctl_info_type == VINFO_BIDI)
31 #define vt_line_is_using_iscii(line) ((line)->ctl_info_type == VINFO_ISCII)
32 #define vt_line_is_using_ot_layout(line) ((line)->ctl_info_type == VINFO_OT_LAYOUT)
33
34 /* You can specify this macro by configure script option. */
35 #if 0
36 #define OPTIMIZE_REDRAWING
37 #endif
38
39 /* --- static functions --- */
40
41 #ifndef NO_DYNAMIC_LOAD_CTL
42
vt_line_set_use_bidi(vt_line_t * line,int flag)43 static int vt_line_set_use_bidi(vt_line_t *line, int flag) {
44 int (*func)(vt_line_t *, int);
45
46 if (!(func = vt_load_ctl_bidi_func(VT_LINE_SET_USE_BIDI))) {
47 return 0;
48 }
49
50 return (*func)(line, flag);
51 }
52
vt_line_bidi_convert_visual_char_index_to_logical(vt_line_t * line,int char_index)53 static int vt_line_bidi_convert_visual_char_index_to_logical(vt_line_t *line, int char_index) {
54 int (*func)(vt_line_t *, int);
55
56 if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_CONVERT_VISUAL_CHAR_INDEX_TO_LOGICAL))) {
57 return char_index;
58 }
59
60 return (*func)(line, char_index);
61 }
62
vt_line_bidi_copy_logical_str(vt_line_t * line,vt_char_t * dst,int beg,u_int len)63 static int vt_line_bidi_copy_logical_str(vt_line_t *line, vt_char_t *dst,
64 int beg, /* visual position */
65 u_int len) {
66 int (*func)(vt_line_t *, vt_char_t *, int, u_int);
67
68 if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_COPY_LOGICAL_STR))) {
69 return 0;
70 }
71
72 return (*func)(line, dst, beg, len);
73 }
74
vt_line_bidi_is_rtl(vt_line_t * line)75 static int vt_line_bidi_is_rtl(vt_line_t *line) {
76 int (*func)(vt_line_t *);
77
78 if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_IS_RTL))) {
79 return 0;
80 }
81
82 return (*func)(line);
83 }
84
vt_bidi_copy(vt_bidi_state_t dst,vt_bidi_state_t src,int optimize_ctl_info)85 static int vt_bidi_copy(vt_bidi_state_t dst, vt_bidi_state_t src, int optimize_ctl_info) {
86 int (*func)(vt_bidi_state_t, vt_bidi_state_t, int);
87
88 if (!(func = vt_load_ctl_bidi_func(VT_BIDI_COPY))) {
89 return 0;
90 }
91
92 return (*func)(dst, src, optimize_ctl_info);
93 }
94
vt_bidi_reset(vt_bidi_state_t state)95 static int vt_bidi_reset(vt_bidi_state_t state) {
96 int (*func)(vt_bidi_state_t);
97
98 if (!(func = vt_load_ctl_bidi_func(VT_BIDI_RESET))) {
99 return 0;
100 }
101
102 return (*func)(state);
103 }
104
vt_line_bidi_render(vt_line_t * line,vt_bidi_mode_t bidi_mode,const char * separators)105 static int vt_line_bidi_render(vt_line_t *line, vt_bidi_mode_t bidi_mode, const char *separators) {
106 int (*func)(vt_line_t *, vt_bidi_mode_t, const char *);
107
108 if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_RENDER))) {
109 return 0;
110 }
111
112 return (*func)(line, bidi_mode, separators);
113 }
114
vt_line_bidi_visual(vt_line_t * line)115 static int vt_line_bidi_visual(vt_line_t *line) {
116 int (*func)(vt_line_t *);
117
118 if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_VISUAL))) {
119 return 0;
120 }
121
122 return (*func)(line);
123 }
124
vt_line_bidi_logical(vt_line_t * line)125 static int vt_line_bidi_logical(vt_line_t *line) {
126 int (*func)(vt_line_t *);
127
128 if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_LOGICAL))) {
129 return 0;
130 }
131
132 return (*func)(line);
133 }
134
vt_line_set_use_iscii(vt_line_t * line,int flag)135 static int vt_line_set_use_iscii(vt_line_t *line, int flag) {
136 int (*func)(vt_line_t *, int);
137
138 if (!(func = vt_load_ctl_iscii_func(VT_LINE_SET_USE_ISCII))) {
139 return 0;
140 }
141
142 return (*func)(line, flag);
143 }
144
vt_line_iscii_convert_visual_char_index_to_logical(vt_line_t * line,int char_index)145 static int vt_line_iscii_convert_visual_char_index_to_logical(vt_line_t *line, int char_index) {
146 int (*func)(vt_line_t *, int);
147
148 if (!(func = vt_load_ctl_iscii_func(VT_LINE_ISCII_CONVERT_VISUAL_CHAR_INDEX_TO_LOGICAL))) {
149 return char_index;
150 }
151
152 return (*func)(line, char_index);
153 }
154
vt_iscii_copy(vt_iscii_state_t dst,vt_iscii_state_t src,int optimize_ctl_info)155 static int vt_iscii_copy(vt_iscii_state_t dst, vt_iscii_state_t src, int optimize_ctl_info) {
156 int (*func)(vt_iscii_state_t, vt_iscii_state_t, int);
157
158 if (!(func = vt_load_ctl_iscii_func(VT_ISCII_COPY))) {
159 return 0;
160 }
161
162 return (*func)(dst, src, optimize_ctl_info);
163 }
164
vt_iscii_reset(vt_iscii_state_t state)165 static int vt_iscii_reset(vt_iscii_state_t state) {
166 int (*func)(vt_iscii_state_t);
167
168 if (!(func = vt_load_ctl_iscii_func(VT_ISCII_RESET))) {
169 return 0;
170 }
171
172 return (*func)(state);
173 }
174
vt_line_iscii_render(vt_line_t * line)175 static int vt_line_iscii_render(vt_line_t *line) {
176 int (*func)(vt_line_t *);
177
178 if (!(func = vt_load_ctl_iscii_func(VT_LINE_ISCII_RENDER))) {
179 return 0;
180 }
181
182 return (*func)(line);
183 }
184
vt_line_iscii_visual(vt_line_t * line)185 static int vt_line_iscii_visual(vt_line_t *line) {
186 int (*func)(vt_line_t *);
187
188 if (!(func = vt_load_ctl_iscii_func(VT_LINE_ISCII_VISUAL))) {
189 return 0;
190 }
191
192 return (*func)(line);
193 }
194
vt_line_iscii_logical(vt_line_t * line)195 static int vt_line_iscii_logical(vt_line_t *line) {
196 int (*func)(vt_line_t *);
197
198 if (!(func = vt_load_ctl_iscii_func(VT_LINE_ISCII_LOGICAL))) {
199 return 0;
200 }
201
202 return (*func)(line);
203 }
204
205 #else /* NO_DYNAMIC_LOAD_CTL */
206
207 #ifndef USE_FRIBIDI
208 #define vt_line_set_use_bidi(line, flag) (0)
209 #define vt_line_bidi_convert_visual_char_index_to_logical(line, char_index) (char_index)
210 #define vt_line_bidi_copy_logical_str(line, dst, beg, len) (0)
211 #define vt_line_bidi_is_rtl(line) (0)
212 #define vt_bidi_copy(dst, src, optimize) (0)
213 #define vt_bidi_reset(state) (0)
214 #define vt_line_bidi_render(line, bidi_mode, separators) (0)
215 #define vt_line_bidi_visual(line) (0)
216 #define vt_line_bidi_logical(line) (0)
217 #else
218 /* Link functions in libctl/vt_*bidi.c */
219 int vt_line_set_use_bidi(vt_line_t *line, int flag);
220 int vt_line_bidi_convert_visual_char_index_to_logical(vt_line_t *line, int char_index);
221 int vt_line_bidi_copy_logical_str(vt_line_t *line, vt_char_t *dst, int beg, u_int len);
222 int vt_line_bidi_is_rtl(vt_line_t *line);
223 int vt_bidi_copy(vt_bidi_state_t dst, vt_bidi_state_t src, int optimize);
224 int vt_bidi_reset(vt_bidi_state_t state);
225 int vt_line_bidi_convert_logical_char_index_to_visual(vt_line_t *line, int char_index,
226 u_int32_t *meet_pos_info);
227 int vt_line_bidi_render(vt_line_t *line, vt_bidi_mode_t bidi_mode, const char *separators);
228 int vt_line_bidi_visual(vt_line_t *line);
229 int vt_line_bidi_logical(vt_line_t *line);
230 #endif /* USE_FRIBIDI */
231
232 #ifndef USE_IND
233 #define vt_line_set_use_iscii(line, flag) (0)
234 #define vt_line_iscii_convert_visual_char_index_to_logical(line, char_index) (char_index)
235 #define vt_iscii_copy(dst, src, optimize) (0)
236 #define vt_iscii_reset(state) (0)
237 #define vt_line_iscii_render(line) (0)
238 #define vt_line_iscii_visual(line) (0)
239 #define vt_line_iscii_logical(line) (0)
240 #else
241 /* Link functions in libctl/vt_*iscii.c */
242 int vt_line_set_use_iscii(vt_line_t *line, int flag);
243 int vt_line_iscii_convert_visual_char_index_to_logical(vt_line_t *line, int visual_char_index);
244 int vt_iscii_copy(vt_iscii_state_t dst, vt_iscii_state_t src, int optimize);
245 int vt_iscii_reset(vt_iscii_state_t state);
246 int vt_line_iscii_convert_logical_char_index_to_visual(vt_line_t *line, int logical_char_index);
247 int vt_line_iscii_render(vt_line_t *line);
248 int vt_line_iscii_visual(vt_line_t *line);
249 int vt_line_iscii_logical(vt_line_t *line);
250 #endif /* USE_IND */
251
252 #endif /* NO_DYNAMIC_LOAD_CTL */
253
254 #ifdef USE_OT_LAYOUT
255
vt_line_set_use_ot_layout(vt_line_t * line,int flag)256 static int vt_line_set_use_ot_layout(vt_line_t *line, int flag) {
257 if (flag) {
258 if (vt_line_is_using_ot_layout(line)) {
259 return 1;
260 } else if (line->ctl_info_type != 0) {
261 return 0;
262 }
263
264 if ((line->ctl_info.ot_layout = vt_ot_layout_new()) == NULL) {
265 return 0;
266 }
267
268 line->ctl_info_type = VINFO_OT_LAYOUT;
269 } else {
270 if (vt_line_is_using_ot_layout(line)) {
271 vt_ot_layout_destroy(line->ctl_info.ot_layout);
272 line->ctl_info_type = 0;
273 }
274 }
275
276 return 1;
277 }
278
279 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_visual(vt_line_t * line)280 static int vt_line_ot_layout_visual(vt_line_t *line) {
281 vt_char_t *src;
282 u_int src_len;
283 vt_char_t *dst;
284 u_int dst_len;
285 int dst_pos;
286 int src_pos;
287
288 if (line->ctl_info.ot_layout->size == 0 || !line->ctl_info.ot_layout->substituted) {
289 #ifdef __DEBUG
290 bl_warn_printf(BL_DEBUG_TAG " Not need to visualize.\n");
291 #endif
292
293 return 1;
294 }
295
296 src_len = line->num_filled_chars;
297 if ((src = vt_str_alloca(src_len)) == NULL) {
298 return 0;
299 }
300 vt_str_init(src, src_len);
301
302 vt_str_copy(src, line->chars, src_len);
303
304 dst_len = line->ctl_info.ot_layout->size;
305 if (line->num_chars < dst_len) {
306 vt_char_t *chars;
307
308 if ((chars = vt_str_new(dst_len))) {
309 /* XXX => shrunk at vt_screen.c and vt_logical_visual_ctl.c */
310 vt_str_destroy(line->chars, line->num_chars);
311 line->chars = chars;
312 line->num_chars = dst_len;
313 } else {
314 line->ctl_info.ot_layout->size = dst_len = line->num_chars;
315 }
316 }
317
318 dst = line->chars;
319
320 src_pos = 0;
321 for (dst_pos = 0; dst_pos < dst_len; dst_pos++) {
322 if (line->ctl_info.ot_layout->num_chars_array[dst_pos] == 0) {
323 /*
324 * (logical)ACD -> (visual)A0CD -> (shaped)abcd
325 * B B
326 * (B is combining char)
327 */
328 vt_char_copy(dst + dst_pos, vt_get_base_char(src + src_pos - 1));
329 vt_char_set_code(dst + dst_pos, 0);
330 } else {
331 u_int count;
332
333 vt_char_copy(dst + dst_pos, src + (src_pos++));
334
335 for (count = 1; count < line->ctl_info.ot_layout->num_chars_array[dst_pos]; count++) {
336 vt_char_t *comb;
337 u_int num;
338
339 #ifdef DEBUG
340 if (vt_char_is_comb(vt_get_base_char(src + src_pos))) {
341 bl_debug_printf(BL_DEBUG_TAG " illegal ot_layout\n");
342 }
343 #endif
344
345 vt_char_combine_simple(dst + dst_pos, vt_get_base_char(src + src_pos));
346
347 comb = vt_get_combining_chars(src + (src_pos++), &num);
348 for (; num > 0; num--) {
349 #ifdef DEBUG
350 if (!vt_char_is_comb(comb)) {
351 bl_debug_printf(BL_DEBUG_TAG " illegal ot_layout\n");
352 }
353 #endif
354 vt_char_combine_simple(dst + dst_pos, comb++);
355 }
356 }
357 }
358 }
359
360 #ifdef DEBUG
361 if (src_pos != src_len) {
362 bl_debug_printf(BL_DEBUG_TAG "vt_line_ot_layout_visual() failed: %d -> %d\n", src_len, src_pos);
363 }
364 #endif
365
366 vt_str_final(src, src_len);
367
368 line->num_filled_chars = dst_pos;
369
370 return 1;
371 }
372
373 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_logical(vt_line_t * line)374 static int vt_line_ot_layout_logical(vt_line_t *line) {
375 vt_char_t *src;
376 u_int src_len;
377 vt_char_t *dst;
378 int src_pos;
379
380 if (line->ctl_info.ot_layout->size == 0 || !line->ctl_info.ot_layout->substituted) {
381 #ifdef __DEBUG
382 bl_warn_printf(BL_DEBUG_TAG " Not need to logicalize.\n");
383 #endif
384
385 return 1;
386 }
387
388 src_len = line->num_filled_chars;
389 if ((src = vt_str_alloca(src_len)) == NULL) {
390 return 0;
391 }
392 vt_str_init(src, src_len);
393
394 vt_str_copy(src, line->chars, src_len);
395 dst = line->chars;
396
397 for (src_pos = 0; src_pos < line->ctl_info.ot_layout->size; src_pos++) {
398 vt_char_t *comb;
399 u_int num;
400
401 if (line->ctl_info.ot_layout->num_chars_array[src_pos] == 0) {
402 continue;
403 }
404
405 if (vt_char_cs(src + src_pos) == ISO10646_UCS4_1_V) {
406 vt_char_set_cs(src + src_pos, ISO10646_UCS4_1);
407 }
408
409 if (line->ctl_info.ot_layout->num_chars_array[src_pos] == 1) {
410 vt_char_copy(dst, src + src_pos);
411 } else {
412 vt_char_copy(dst, vt_get_base_char(src + src_pos));
413
414 comb = vt_get_combining_chars(src + src_pos, &num);
415 for (; num > 0; num--, comb++) {
416 if (vt_char_cs(comb) == ISO10646_UCS4_1_V) {
417 vt_char_set_cs(comb, ISO10646_UCS4_1);
418 }
419
420 if (vt_char_is_comb(comb)) {
421 vt_char_combine_simple(dst, comb);
422 } else {
423 vt_char_copy(++dst, comb);
424 }
425 }
426 }
427
428 dst++;
429 }
430
431 vt_str_final(src, src_len);
432
433 line->num_filled_chars = dst - line->chars;
434
435 return 1;
436 }
437
438 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_convert_logical_char_index_to_visual(vt_line_t * line,int logical_char_index)439 static int vt_line_ot_layout_convert_logical_char_index_to_visual(vt_line_t *line,
440 int logical_char_index) {
441 int visual_char_index;
442
443 if (vt_line_is_empty(line)) {
444 return 0;
445 }
446
447 if (line->ctl_info.ot_layout->size == 0 || !line->ctl_info.ot_layout->substituted) {
448 #ifdef __DEBUG
449 bl_debug_printf(BL_DEBUG_TAG " logical char_index is same as visual one.\n");
450 #endif
451 return logical_char_index;
452 }
453
454 for (visual_char_index = 0; visual_char_index < line->ctl_info.ot_layout->size;
455 visual_char_index++) {
456 if ((logical_char_index -= line->ctl_info.ot_layout->num_chars_array[visual_char_index]) < 0) {
457 break;
458 }
459 }
460
461 return visual_char_index;
462 }
463
464 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_convert_visual_char_index_to_logical(vt_line_t * line,int visual_char_index)465 static int vt_line_ot_layout_convert_visual_char_index_to_logical(vt_line_t *line,
466 int visual_char_index) {
467 int logical_char_index;
468 int count;
469
470 if (vt_line_is_empty(line)) {
471 return 0;
472 }
473
474 if (line->ctl_info.ot_layout->size == 0 || !line->ctl_info.ot_layout->substituted) {
475 #ifdef __DEBUG
476 bl_debug_printf(BL_DEBUG_TAG " visual char_index is same as logical one.\n");
477 #endif
478 return visual_char_index;
479 }
480
481 if (line->ctl_info.ot_layout->size - 1 < visual_char_index) {
482 visual_char_index = line->ctl_info.ot_layout->size - 1;
483 }
484
485 logical_char_index = 0;
486 for (count = 0; count < visual_char_index; count++) {
487 logical_char_index += line->ctl_info.ot_layout->num_chars_array[count];
488 }
489
490 return logical_char_index;
491 }
492
493 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_render(vt_line_t * line,void * term)494 static int vt_line_ot_layout_render(vt_line_t *line, /* is always modified */
495 void *term) {
496 int ret;
497 int visual_mod_beg;
498 int visual_mod_end;
499
500 /*
501 * Lower case: ASCII
502 * Upper case: GLYPH INDEX
503 * (Logical) AAA == (Visual) BBBBB
504 * => (Logical) aaa == (Visual) aaa
505 * In this case vt_line_is_cleared_to_end() returns 0, so "BB" remains on
506 * the screen unless following vt_line_set_modified().
507 */
508 visual_mod_beg = vt_line_get_beg_of_modified(line);
509 if (line->ctl_info.ot_layout->substituted) {
510 visual_mod_beg = vt_line_ot_layout_convert_logical_char_index_to_visual(line, visual_mod_beg);
511 }
512
513 if (vt_line_is_real_modified(line)) {
514 int char_index;
515 int complex_shape = line->ctl_info.ot_layout->complex_shape;
516 int has_var_width_char = line->ctl_info.ot_layout->has_var_width_char;
517 int count;
518
519 line->ctl_info.ot_layout->term = term;
520
521 if ((ret = vt_ot_layout(line->ctl_info.ot_layout, line->chars, line->num_filled_chars)) <= 0) {
522 if (complex_shape || has_var_width_char) {
523 vt_line_set_modified_all(line);
524 }
525
526 return ret;
527 }
528
529 complex_shape |= line->ctl_info.ot_layout->complex_shape;
530 has_var_width_char |= line->ctl_info.ot_layout->has_var_width_char;
531
532 if (line->ctl_info.ot_layout->substituted) {
533 int beg;
534
535 if ((beg = vt_line_ot_layout_convert_logical_char_index_to_visual(
536 line, vt_line_get_beg_of_modified(line))) < visual_mod_beg) {
537 visual_mod_beg = beg;
538 }
539 }
540
541 if (has_var_width_char) {
542 visual_mod_end = line->num_chars;
543 } else {
544 visual_mod_end = vt_line_ot_layout_convert_logical_char_index_to_visual(line,
545 vt_line_get_end_of_modified(line));
546 }
547
548 if (complex_shape) {
549 /*
550 * XXX
551 *
552 * Input Logical Visual
553 * ! => ! => !
554 * ^ ^
555 * = => != => =/=
556 * ^ ^^^
557 * ('=' after '!' should be redrawn in logical, but the first '!' should
558 * be also redrawn in visual.)
559 */
560 for (count = 0; visual_mod_beg > 0 && count < 4; count++, visual_mod_beg--) {
561 if (vt_char_code(line->chars + visual_mod_beg - 1) == 0x20 /* SP */) {
562 break;
563 }
564 }
565
566 /* If trailing characters in this line are all spaces, visual_mod_end is not modified. */
567 for (char_index = visual_mod_end + 1; char_index < line->num_filled_chars; char_index++) {
568 if (vt_char_code(line->chars + char_index) != 0x20 /* SP */) {
569 visual_mod_end = line->num_chars;
570 break;
571 }
572 }
573 }
574 } else {
575 visual_mod_end = vt_line_ot_layout_convert_logical_char_index_to_visual(line,
576 vt_line_get_end_of_modified(line));
577 }
578
579 vt_line_set_modified(line, visual_mod_beg, visual_mod_end);
580
581 return 1;
582 }
583
584 #endif /* USE_OT_LAYOUT */
585
set_real_modified(vt_line_t * line,int beg_char_index,int end_char_index)586 static void set_real_modified(vt_line_t *line, int beg_char_index, int end_char_index) {
587 vt_line_set_modified(line, beg_char_index, end_char_index);
588 line->is_modified = 2;
589 }
590
copy_line(vt_line_t * dst,vt_line_t * src,int optimize_ctl_info)591 static void copy_line(vt_line_t *dst, vt_line_t *src, int optimize_ctl_info) {
592 u_int copy_len;
593
594 #ifdef DEBUG
595 if (dst == src) {
596 bl_error_printf("copy_line() forbids src == dst\n");
597 abort();
598 }
599 #endif
600
601 copy_len = BL_MIN(src->num_filled_chars, dst->num_chars);
602
603 vt_str_copy(dst->chars, src->chars, copy_len);
604 dst->num_filled_chars = copy_len;
605
606 dst->change_beg_col = BL_MIN(src->change_beg_col, dst->num_chars);
607 dst->change_end_col = BL_MIN(src->change_end_col, dst->num_chars);
608
609 dst->is_modified = src->is_modified;
610 dst->is_continued_to_next = src->is_continued_to_next;
611 dst->size_attr = src->size_attr;
612 dst->mark = src->mark;
613
614 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_FRIBIDI)
615 if (vt_line_is_using_bidi(src)) {
616 if (vt_line_is_using_bidi(dst) || vt_line_set_use_bidi(dst, 1)) {
617 /*
618 * Don't use vt_line_bidi_render() here,
619 * or it is impossible to call this function in visual context.
620 */
621 if (dst->num_chars < src->num_filled_chars) {
622 #ifdef DEBUG
623 bl_debug_printf(BL_DEBUG_TAG " Not copy vt_bidi.\n");
624 #endif
625 /*
626 * XXX
627 * Isn't set_real_modified(dst, 0, END_CHAR_INDEX(dst)) necessary here
628 * to force ctl_render() ?
629 */
630 } else if (vt_bidi_copy(dst->ctl_info.bidi, src->ctl_info.bidi, optimize_ctl_info) == -1) {
631 dst->ctl_info_type = 0;
632 dst->ctl_info.bidi = NULL;
633 }
634 }
635 } else if (vt_line_is_using_bidi(dst)) {
636 vt_line_set_use_bidi(dst, 0);
637 }
638 #endif
639
640 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_IND)
641 if (vt_line_is_using_iscii(src)) {
642 if (vt_line_is_using_iscii(dst) || vt_line_set_use_iscii(dst, 1)) {
643 /*
644 * Don't use vt_line_iscii_render() here,
645 * or it is impossible to call this function in visual context.
646 */
647 if (dst->num_chars < src->num_filled_chars) {
648 #ifdef DEBUG
649 bl_debug_printf(BL_DEBUG_TAG " Not copy vt_iscii.\n");
650 #endif
651 /*
652 * XXX
653 * Isn't set_real_modified(dst, 0, END_CHAR_INDEX(dst)) necessary here
654 * to force ctl_render() ?
655 */
656 } else if (vt_iscii_copy(dst->ctl_info.iscii, src->ctl_info.iscii, optimize_ctl_info) == -1) {
657 dst->ctl_info_type = 0;
658 dst->ctl_info.iscii = NULL;
659 }
660 }
661 } else if (vt_line_is_using_iscii(dst)) {
662 vt_line_set_use_iscii(dst, 0);
663 }
664 #endif
665
666 #ifdef USE_OT_LAYOUT
667 if (vt_line_is_using_ot_layout(src)) {
668 if (vt_line_is_using_ot_layout(dst) || vt_line_set_use_ot_layout(dst, 1)) {
669 /*
670 * Don't use vt_line_ot_layout_render() here,
671 * or it is impossible to call this function in visual context.
672 */
673 if (dst->num_chars < src->num_filled_chars) {
674 #ifdef DEBUG
675 bl_debug_printf(BL_DEBUG_TAG " Not copy vt_ot_layout.\n");
676 #endif
677 /*
678 * XXX
679 * Isn't set_real_modified(dst, 0, END_CHAR_INDEX(dst)) necessary here
680 * to force ctl_render() ?
681 */
682 } else if (vt_ot_layout_copy(dst->ctl_info.ot_layout, src->ctl_info.ot_layout,
683 optimize_ctl_info) == -1) {
684 dst->ctl_info_type = 0;
685 dst->ctl_info.ot_layout = NULL;
686 }
687 }
688 } else if (vt_line_is_using_ot_layout(dst)) {
689 vt_line_set_use_ot_layout(dst, 0);
690 }
691 #endif
692 }
693
694 /* --- global functions --- */
695
696 /*
697 * Functions which doesn't have to care about visual order.
698 */
699
vt_line_init(vt_line_t * line,u_int num_chars)700 int vt_line_init(vt_line_t *line, u_int num_chars) {
701 memset(line, 0, sizeof(vt_line_t));
702
703 if ((line->chars = vt_str_new(num_chars)) == NULL) {
704 return 0;
705 }
706
707 line->num_chars = num_chars;
708
709 return 1;
710 }
711
712 /* For vt_log_add() */
vt_line_clone(vt_line_t * clone,vt_line_t * orig,u_int num_chars)713 int vt_line_clone(vt_line_t *clone, vt_line_t *orig, u_int num_chars) {
714 if (vt_line_init(clone, num_chars)) {
715 copy_line(clone, orig, 1 /* clone->ctl_info can be uncopied. */);
716
717 return 1;
718 } else {
719 return 0;
720 }
721 }
722
vt_line_final(vt_line_t * line)723 void vt_line_final(vt_line_t *line) {
724 if (vt_line_is_using_bidi(line)) {
725 vt_line_set_use_bidi(line, 0);
726 } else if (vt_line_is_using_iscii(line)) {
727 vt_line_set_use_iscii(line, 0);
728 }
729 #ifdef USE_OT_LAYOUT
730 else if (vt_line_is_using_ot_layout(line)) {
731 vt_line_set_use_ot_layout(line, 0);
732 }
733 #endif
734
735 if (line->chars) {
736 vt_str_destroy(line->chars, line->num_chars);
737 }
738 }
739
740 /*
741 * return: actually broken chars.
742 */
vt_line_break_boundary(vt_line_t * line,u_int size)743 u_int vt_line_break_boundary(vt_line_t *line, u_int size) {
744 int count;
745
746 if (line->num_filled_chars + size > line->num_chars) {
747 /* over line length */
748
749 #ifdef DEBUG
750 bl_warn_printf(BL_DEBUG_TAG " breaking from col %d by size %d failed.",
751 line->num_filled_chars, size);
752 #endif
753
754 size = line->num_chars - line->num_filled_chars;
755
756 #ifdef DEBUG
757 bl_msg_printf(" ... size modified -> %d\n", size);
758 #endif
759 }
760
761 if (size == 0) {
762 /* nothing is done */
763
764 return 0;
765 }
766
767 /* padding spaces */
768 for (count = line->num_filled_chars; count < line->num_filled_chars + size; count++) {
769 vt_char_copy(line->chars + count, vt_sp_ch());
770 }
771
772 #if 0
773 set_real_modified(line, END_CHAR_INDEX(line) + 1, END_CHAR_INDEX(line) + size);
774 #else
775 if (vt_line_is_using_ctl(line) && !vt_line_is_real_modified(line)) {
776 /* ctl_render_line() should be called in ctl_render() in
777 * vt_logical_visual.c. */
778 set_real_modified(line, END_CHAR_INDEX(line) + size, END_CHAR_INDEX(line) + size);
779 }
780 #endif
781
782 line->num_filled_chars += size;
783
784 return size;
785 }
786
vt_line_assure_boundary(vt_line_t * line,int char_index)787 int vt_line_assure_boundary(vt_line_t *line, int char_index) {
788 if (char_index >= line->num_filled_chars) {
789 u_int brk_size;
790
791 brk_size = char_index - line->num_filled_chars + 1;
792
793 if (vt_line_break_boundary(line, brk_size) < brk_size) {
794 return 0;
795 }
796 }
797
798 return 1;
799 }
800
vt_line_reset(vt_line_t * line)801 void vt_line_reset(vt_line_t *line) {
802 if (IS_EMPTY(line)) {
803 /* already reset */
804 return;
805 }
806
807 #ifdef OPTIMIZE_REDRAWING
808 {
809 int count;
810
811 count = END_CHAR_INDEX(line);
812 while (1) {
813 if (!vt_char_equal(line->chars + count, vt_sp_ch())) {
814 set_real_modified(line, 0, count);
815
816 break;
817 } else if (--count < 0) {
818 break;
819 }
820 }
821 }
822 #else
823 set_real_modified(line, 0, END_CHAR_INDEX(line));
824 #endif
825
826 line->num_filled_chars = 0;
827
828 if (vt_line_is_using_bidi(line)) {
829 vt_bidi_reset(line->ctl_info.bidi);
830 } else if (vt_line_is_using_iscii(line)) {
831 vt_iscii_reset(line->ctl_info.iscii);
832 }
833 #ifdef USE_OT_LAYOUT
834 else if (vt_line_is_using_ot_layout(line)) {
835 vt_ot_layout_reset(line->ctl_info.ot_layout);
836 }
837 #endif
838
839 line->is_continued_to_next = 0;
840 line->size_attr = 0;
841 }
842
vt_line_clear(vt_line_t * line,int char_index)843 void vt_line_clear(vt_line_t *line, int char_index) {
844 if (char_index >= line->num_filled_chars) {
845 return;
846 }
847
848 #ifdef OPTIMIZE_REDRAWING
849 {
850 int count;
851
852 count = END_CHAR_INDEX(line);
853 while (1) {
854 if (!vt_char_equal(line->chars + count, vt_sp_ch())) {
855 set_real_modified(line, char_index, count);
856
857 break;
858 } else if (--count < char_index) {
859 break;
860 }
861 }
862 }
863 #else
864 set_real_modified(line, char_index, END_CHAR_INDEX(line));
865 #endif
866
867 vt_char_copy(line->chars + char_index, vt_sp_ch());
868 line->num_filled_chars = char_index + 1;
869 line->is_continued_to_next = 0;
870 line->size_attr = 0;
871 }
872
vt_line_clear_with(vt_line_t * line,int char_index,vt_char_t * ch)873 int vt_line_clear_with(vt_line_t *line, int char_index, vt_char_t *ch) {
874 line->is_continued_to_next = 0;
875
876 return vt_line_fill(
877 line, ch, char_index,
878 (line->num_chars - vt_str_cols(line->chars, char_index)) / vt_char_cols(ch));
879 }
880
vt_line_overwrite(vt_line_t * line,int beg_char_index,vt_char_t * chars,u_int len,u_int cols)881 int vt_line_overwrite(vt_line_t *line, int beg_char_index, /* >= line->num_filled_chars is OK */
882 vt_char_t *chars, u_int len, u_int cols) {
883 int count;
884 u_int cols_to_beg;
885 u_int cols_rest;
886 u_int padding;
887 u_int new_len;
888 u_int copy_len;
889 vt_char_t *copy_src;
890
891 if (len == 0) {
892 return 1;
893 }
894
895 if (beg_char_index + len > line->num_chars) {
896 if (beg_char_index >= line->num_chars) {
897 #ifdef DEBUG
898 bl_warn_printf(BL_DEBUG_TAG " beg[%d] is over num_chars[%d].\n", beg_char_index,
899 line->num_chars);
900 #endif
901
902 return 0;
903 }
904
905 #ifdef DEBUG
906 bl_warn_printf(BL_DEBUG_TAG " beg_char_index[%d] + len[%d] is over num_chars[%d].\n",
907 beg_char_index, len, line->num_chars);
908 #endif
909
910 len = line->num_chars - beg_char_index;
911 }
912
913 if (beg_char_index > 0) {
914 vt_line_assure_boundary(line, beg_char_index - 1);
915 }
916
917 #ifdef OPTIMIZE_REDRAWING
918 if (len <= line->num_filled_chars - beg_char_index) {
919 if (vt_str_equal(line->chars + beg_char_index, chars, len)) {
920 return 1;
921 }
922 } else {
923 if (vt_str_equal(line->chars + beg_char_index, chars,
924 line->num_filled_chars - beg_char_index)) {
925 chars += (line->num_filled_chars - beg_char_index);
926 len -= (line->num_filled_chars - beg_char_index);
927 beg_char_index = line->num_filled_chars;
928
929 count = 0;
930 while (1) {
931 if (!vt_char_equal(chars + count, vt_sp_ch())) {
932 break;
933 } else if (++count >= len) {
934 vt_str_copy(line->chars + beg_char_index, chars, len);
935 line->num_filled_chars = beg_char_index + len;
936
937 /* Not necessary vt_line_set_modified() */
938
939 return 1;
940 }
941 }
942 }
943 }
944 #endif
945
946 cols_to_beg = vt_str_cols(line->chars, beg_char_index);
947
948 if (cols_to_beg + cols < line->num_chars) {
949 int char_index;
950
951 char_index = vt_convert_col_to_char_index(line, &cols_rest, cols_to_beg + cols, 0);
952
953 if (0 < cols_rest && cols_rest < vt_char_cols(line->chars + char_index)) {
954 padding = vt_char_cols(line->chars + char_index) - cols_rest;
955 char_index++;
956 } else {
957 padding = 0;
958 }
959
960 if (line->num_filled_chars > char_index) {
961 copy_len = line->num_filled_chars - char_index;
962 } else {
963 copy_len = 0;
964 }
965
966 copy_src = line->chars + char_index;
967 } else {
968 padding = 0;
969 copy_len = 0;
970 copy_src = NULL;
971 }
972
973 new_len = beg_char_index + len + padding + copy_len;
974
975 if (new_len > line->num_chars) {
976 #ifdef DEBUG
977 bl_warn_printf(BL_DEBUG_TAG " new line len %d(beg %d ow %d padding %d copy %d) is overflowed\n",
978 new_len, beg_char_index, len, padding, copy_len);
979 #endif
980
981 new_len = line->num_chars;
982
983 if (new_len > padding + beg_char_index + len) {
984 copy_len = new_len - padding - beg_char_index - len;
985 } else {
986 copy_len = 0;
987 padding = new_len - beg_char_index - len;
988 }
989
990 #ifdef DEBUG
991 bl_msg_printf(" ... modified -> new_len %d , copy_len %d\n", new_len, copy_len);
992 #endif
993 }
994
995 if (copy_len > 0) {
996 /* making space */
997 vt_str_copy(line->chars + beg_char_index + len + padding, copy_src, copy_len);
998 }
999
1000 for (count = 0; count < padding; count++) {
1001 vt_char_copy(line->chars + beg_char_index + len + count, vt_sp_ch());
1002 }
1003
1004 vt_str_copy(line->chars + beg_char_index, chars, len);
1005
1006 line->num_filled_chars = new_len;
1007
1008 set_real_modified(line, beg_char_index, beg_char_index + len + padding - 1);
1009
1010 return 1;
1011 }
1012
1013 /*
1014 * Not used for now.
1015 */
1016 #if 0
1017 int vt_line_overwrite_all(vt_line_t *line, vt_char_t *chars, int len) {
1018 set_real_modified(line, 0, END_CHAR_INDEX(line));
1019
1020 vt_str_copy(line->chars, chars, len);
1021 line->num_filled_chars = len;
1022
1023 set_real_modified(line, 0, END_CHAR_INDEX(line));
1024
1025 return 1;
1026 }
1027 #endif
1028
vt_line_fill(vt_line_t * line,vt_char_t * ch,int beg,u_int num)1029 int vt_line_fill(vt_line_t *line, vt_char_t *ch, int beg, /* >= line->num_filled_chars is OK */
1030 u_int num) {
1031 int count;
1032 int char_index;
1033 u_int left_cols;
1034 u_int copy_len;
1035
1036 if (num == 0) {
1037 return 1;
1038 }
1039
1040 if (beg >= line->num_chars) {
1041 #ifdef DEBUG
1042 bl_warn_printf(BL_DEBUG_TAG " beg[%d] is over num_chars[%d].\n", beg, line->num_chars);
1043 #endif
1044
1045 return 0;
1046 }
1047
1048 if (beg > 0) {
1049 vt_line_assure_boundary(line, beg - 1);
1050 }
1051
1052 #ifdef OPTIMIZE_REDRAWING
1053 count = 0;
1054 while (1) {
1055 if (!vt_char_equal(line->chars + beg + count, ch)) {
1056 beg += count;
1057 num -= count;
1058
1059 if (beg + num <= line->num_filled_chars) {
1060 count = 0;
1061 while (1) {
1062 if (!vt_char_equal(line->chars + beg + num - 1 - count, ch)) {
1063 num -= count;
1064
1065 break;
1066 } else if (count++ == num) {
1067 /* Never happens */
1068
1069 return 1;
1070 }
1071 }
1072 }
1073
1074 break;
1075 } else if (++count >= num) {
1076 return 1;
1077 } else if (beg + count == line->num_filled_chars) {
1078 beg += count;
1079 num -= count;
1080
1081 break;
1082 }
1083 }
1084 #endif
1085
1086 num = BL_MIN(num, line->num_chars - beg);
1087
1088 char_index = beg;
1089 left_cols = num * vt_char_cols(ch);
1090
1091 while (1) {
1092 if (char_index >= line->num_filled_chars) {
1093 left_cols = 0;
1094 copy_len = 0;
1095
1096 break;
1097 } else if (left_cols < vt_char_cols(line->chars + char_index)) {
1098 if (beg + num + left_cols > line->num_chars) {
1099 left_cols = line->num_chars - beg - num;
1100 copy_len = 0;
1101 } else {
1102 copy_len = line->num_filled_chars - char_index - left_cols;
1103
1104 if (beg + num + left_cols + copy_len > line->num_chars) {
1105 /*
1106 * line->num_chars is equal to or larger than
1107 * beg + num + left_cols since
1108 * 'if( beg + num + left_cols > line->num_chars)'
1109 * is already passed here.
1110 */
1111 copy_len = line->num_chars - beg - num - left_cols;
1112 }
1113 }
1114
1115 char_index += (left_cols / vt_char_cols(ch));
1116
1117 break;
1118 } else {
1119 left_cols -= vt_char_cols(line->chars + char_index);
1120 char_index++;
1121 }
1122 }
1123
1124 if (copy_len > 0) {
1125 /* making space */
1126 vt_str_copy(line->chars + beg + num + left_cols, line->chars + char_index, copy_len);
1127 }
1128
1129 char_index = beg;
1130
1131 for (count = 0; count < num; count++) {
1132 vt_char_copy(&line->chars[char_index++], ch);
1133 }
1134
1135 /* padding */
1136 for (count = 0; count < left_cols; count++) {
1137 vt_char_copy(&line->chars[char_index++], vt_sp_ch());
1138 }
1139
1140 line->num_filled_chars = char_index + copy_len;
1141
1142 set_real_modified(line, beg, beg + num + left_cols);
1143
1144 return 1;
1145 }
1146
vt_char_at(vt_line_t * line,int at)1147 vt_char_t *vt_char_at(vt_line_t *line, int at) {
1148 if (at >= line->num_filled_chars) {
1149 return NULL;
1150 } else {
1151 return line->chars + at;
1152 }
1153 }
1154
vt_line_set_modified(vt_line_t * line,int beg_char_index,int end_char_index)1155 int vt_line_set_modified(vt_line_t *line, int beg_char_index, int end_char_index) {
1156 int count;
1157 int beg_col;
1158 int end_col;
1159
1160 if (beg_char_index > end_char_index) {
1161 #ifdef DEBUG
1162 bl_warn_printf(BL_DEBUG_TAG " beg_char_index %d > end_char_index %d\n", beg_char_index,
1163 end_char_index);
1164 #endif
1165
1166 return 0;
1167 }
1168
1169 if (beg_char_index >= line->num_filled_chars) {
1170 beg_char_index = END_CHAR_INDEX(line);
1171 }
1172
1173 beg_col = 0;
1174 for (count = 0; count < beg_char_index; count++) {
1175 beg_col += vt_char_cols(line->chars + count);
1176 }
1177
1178 if (end_char_index >= line->num_filled_chars) {
1179 /*
1180 * '* 2' assures change_end_col should point over the end of line.
1181 * If triple width(or wider) characters(!) were to exist, this hack would
1182 * make
1183 * no sense...
1184 */
1185 end_col = line->num_chars * 2;
1186 } else {
1187 end_col = beg_col;
1188 for (; count <= end_char_index; count++) {
1189 /*
1190 * This will be executed at least once, because beg_char_index is never
1191 * greater than end_char_index.
1192 */
1193 end_col += vt_char_cols(line->chars + count);
1194 }
1195
1196 /*
1197 * If vt_char_cols() returns 0, beg_col can be equals to end_col here.
1198 * If beg_col is equals to end_col, don't minus end_col.
1199 */
1200 if (beg_col < end_col) {
1201 end_col--;
1202 }
1203 }
1204
1205 if (line->is_modified) {
1206 if (beg_col < line->change_beg_col) {
1207 line->change_beg_col = beg_col;
1208 }
1209
1210 if (end_col > line->change_end_col) {
1211 line->change_end_col = end_col;
1212 }
1213 } else {
1214 line->change_beg_col = beg_col;
1215 line->change_end_col = end_col;
1216
1217 line->is_modified = 1;
1218 }
1219
1220 return 1;
1221 }
1222
vt_line_set_modified_all(vt_line_t * line)1223 int vt_line_set_modified_all(vt_line_t *line) {
1224 line->change_beg_col = 0;
1225
1226 /*
1227 * '* 2' assures change_end_col should point over the end of line.
1228 * If triple width(or wider) characters(!) were to exist, this hack would make
1229 * no sense...
1230 */
1231 line->change_end_col = line->num_chars * 2;
1232
1233 /* Don't overwrite if line->is_modified == 2 (real modified) */
1234 if (!line->is_modified) {
1235 line->is_modified = 1;
1236 }
1237
1238 return 1;
1239 }
1240
vt_line_is_cleared_to_end(vt_line_t * line)1241 int vt_line_is_cleared_to_end(vt_line_t *line) {
1242 if (vt_line_get_num_filled_cols(line) < line->change_end_col + 1) {
1243 return 1;
1244 } else {
1245 return 0;
1246 }
1247 }
1248
vt_line_is_modified(vt_line_t * line)1249 int vt_line_is_modified(vt_line_t *line) { return line->is_modified; }
1250
vt_line_get_beg_of_modified(vt_line_t * line)1251 int vt_line_get_beg_of_modified(vt_line_t *line) {
1252 if (IS_EMPTY(line)) {
1253 return 0;
1254 } else {
1255 return vt_convert_col_to_char_index(line, NULL, line->change_beg_col, 0);
1256 }
1257 }
1258
vt_line_get_end_of_modified(vt_line_t * line)1259 int vt_line_get_end_of_modified(vt_line_t *line) {
1260 if (IS_EMPTY(line)) {
1261 return 0;
1262 } else {
1263 return vt_convert_col_to_char_index(line, NULL, line->change_end_col, 0);
1264 }
1265 }
1266
vt_line_get_num_redrawn_chars(vt_line_t * line,int to_end)1267 u_int vt_line_get_num_redrawn_chars(vt_line_t *line, int to_end) {
1268 if (IS_EMPTY(line)) {
1269 return 0;
1270 } else if (to_end) {
1271 return line->num_filled_chars - vt_line_get_beg_of_modified(line);
1272 } else {
1273 return vt_line_get_end_of_modified(line) - vt_line_get_beg_of_modified(line) + 1;
1274 }
1275 }
1276
vt_line_set_updated(vt_line_t * line)1277 void vt_line_set_updated(vt_line_t *line) {
1278 line->is_modified = 0;
1279
1280 line->change_beg_col = 0;
1281 line->change_end_col = 0;
1282 }
1283
vt_line_is_continued_to_next(vt_line_t * line)1284 int vt_line_is_continued_to_next(vt_line_t *line) { return line->is_continued_to_next; }
1285
vt_line_set_continued_to_next(vt_line_t * line,int flag)1286 void vt_line_set_continued_to_next(vt_line_t *line, int flag) { line->is_continued_to_next = flag; }
1287
vt_convert_char_index_to_col(vt_line_t * line,int char_index,int flag)1288 int vt_convert_char_index_to_col(vt_line_t *line, int char_index, int flag /* BREAK_BOUNDARY */
1289 ) {
1290 int count;
1291 int col;
1292
1293 if (char_index >= line->num_chars) {
1294 #ifdef __DEBUG
1295 bl_debug_printf(BL_DEBUG_TAG
1296 " char index %d is larger than num_chars(%d) ... modified -> %d.\n",
1297 char_index, line->num_chars, line->num_chars - 1);
1298 #endif
1299
1300 char_index = line->num_chars - 1;
1301 }
1302
1303 col = 0;
1304
1305 if ((flag & BREAK_BOUNDARY) && line->num_filled_chars <= char_index) {
1306 for (count = 0; count < line->num_filled_chars; count++) {
1307 col += vt_char_cols(line->chars + count);
1308 }
1309
1310 col += (char_index - count);
1311 } else if (line->num_filled_chars > 0) {
1312 /*
1313 * excluding the width of the last char.
1314 */
1315 int end = BL_MIN(char_index, END_CHAR_INDEX(line));
1316
1317 for (count = 0; count < end; count++) {
1318 col += vt_char_cols(line->chars + count);
1319 }
1320 }
1321
1322 return col;
1323 }
1324
vt_convert_col_to_char_index(vt_line_t * line,u_int * cols_rest,int col,int flag)1325 int vt_convert_col_to_char_index(vt_line_t *line, u_int *cols_rest, int col,
1326 int flag /* BREAK_BOUNDARY */
1327 ) {
1328 int char_index;
1329
1330 #ifdef DEBUG
1331 if (col >= line->num_chars * 2 && cols_rest) {
1332 bl_warn_printf(BL_DEBUG_TAG
1333 " Since col [%d] is over line->num_chars * 2 [%d],"
1334 " cols_rest will be corrupt...\n",
1335 col, line->num_chars * 2);
1336 }
1337 #endif
1338
1339 for (char_index = 0; char_index + 1 < line->num_filled_chars; char_index++) {
1340 int cols;
1341
1342 cols = vt_char_cols(line->chars + char_index);
1343 if (col < cols) {
1344 goto end;
1345 }
1346
1347 col -= cols;
1348 }
1349
1350 if (flag & BREAK_BOUNDARY) {
1351 char_index += col;
1352 col = 0;
1353 }
1354
1355 end:
1356 if (cols_rest != NULL) {
1357 *cols_rest = col;
1358 }
1359
1360 return char_index;
1361 }
1362
vt_line_reverse_color(vt_line_t * line,int char_index)1363 int vt_line_reverse_color(vt_line_t *line, int char_index) {
1364 if (char_index >= line->num_filled_chars) {
1365 return 0;
1366 }
1367
1368 if (vt_char_reverse_color(line->chars + char_index)) {
1369 vt_line_set_modified(line, char_index, char_index);
1370 }
1371
1372 return 1;
1373 }
1374
vt_line_restore_color(vt_line_t * line,int char_index)1375 int vt_line_restore_color(vt_line_t *line, int char_index) {
1376 if (char_index >= line->num_filled_chars) {
1377 return 0;
1378 }
1379
1380 if (vt_char_restore_color(line->chars + char_index)) {
1381 vt_line_set_modified(line, char_index, char_index);
1382 }
1383
1384 return 1;
1385 }
1386
1387 /*
1388 * This copys a line as it is and doesn't care about visual order.
1389 * But bidi parameters are also copyed as it is.
1390 */
vt_line_copy(vt_line_t * dst,vt_line_t * src)1391 int vt_line_copy(vt_line_t *dst, /* should be initialized ahead */
1392 vt_line_t *src) {
1393 copy_line(dst, src, 0);
1394
1395 return 1;
1396 }
1397
vt_line_swap(vt_line_t * line1,vt_line_t * line2)1398 int vt_line_swap(vt_line_t *line1, vt_line_t *line2) {
1399 vt_line_t tmp;
1400
1401 tmp = *line1;
1402 *line1 = *line2;
1403 *line2 = tmp;
1404
1405 return 1;
1406 }
1407
vt_line_share(vt_line_t * dst,vt_line_t * src)1408 int vt_line_share(vt_line_t *dst, vt_line_t *src) {
1409 memcpy(dst, src, sizeof(vt_line_t));
1410
1411 return 1;
1412 }
1413
vt_line_is_empty(vt_line_t * line)1414 int vt_line_is_empty(vt_line_t *line) { return IS_EMPTY(line); }
1415
vt_line_beg_char_index_regarding_rtl(vt_line_t * line)1416 int vt_line_beg_char_index_regarding_rtl(vt_line_t *line) {
1417 int char_index;
1418
1419 if (vt_line_is_rtl(line)) {
1420 for (char_index = 0; char_index < line->num_filled_chars; char_index++) {
1421 if (!vt_char_equal(line->chars + char_index, vt_sp_ch())) {
1422 return char_index;
1423 }
1424 }
1425 }
1426
1427 return 0;
1428 }
1429
vt_line_end_char_index(vt_line_t * line)1430 int vt_line_end_char_index(vt_line_t *line) {
1431 if (IS_EMPTY(line)) {
1432 #ifdef __DEBUG
1433 bl_debug_printf(BL_DEBUG_TAG " num_filled_chars is 0.\n");
1434 #endif
1435
1436 return 0;
1437 } else {
1438 return line->num_filled_chars - 1;
1439 }
1440 }
1441
vt_line_get_num_filled_cols(vt_line_t * line)1442 u_int vt_line_get_num_filled_cols(vt_line_t *line) {
1443 return vt_str_cols(line->chars, line->num_filled_chars);
1444 }
1445
vt_line_get_num_filled_chars_except_sp_with_func(vt_line_t * line,int (* func)(vt_char_t *,vt_char_t *))1446 u_int vt_line_get_num_filled_chars_except_sp_with_func(vt_line_t *line,
1447 int (*func)(vt_char_t *, vt_char_t *)) {
1448 if (IS_EMPTY(line)) {
1449 return 0;
1450 } else if (vt_line_is_rtl(line) || line->is_continued_to_next) {
1451 return line->num_filled_chars;
1452 } else {
1453 int char_index;
1454
1455 for (char_index = END_CHAR_INDEX(line); char_index >= 0; char_index--) {
1456 #if 1
1457 /* >= 3.0.6 */
1458 if (!(*func)(line->chars + char_index, vt_sp_ch()))
1459 #else
1460 /* <= 3.0.5 */
1461 if (!vt_char_equal(line->chars + char_index, vt_sp_ch()))
1462 #endif
1463 {
1464 return char_index + 1;
1465 }
1466 }
1467
1468 return 0;
1469 }
1470 }
1471
vt_line_set_size_attr(vt_line_t * line,int size_attr)1472 void vt_line_set_size_attr(vt_line_t *line, int size_attr) {
1473 if (line->size_attr != size_attr) {
1474 line->size_attr = size_attr;
1475 vt_line_set_modified_all(line);
1476 }
1477 }
1478
vt_line_convert_visual_char_index_to_logical(vt_line_t * line,int char_index)1479 int vt_line_convert_visual_char_index_to_logical(vt_line_t *line, int char_index) {
1480 if (vt_line_is_using_bidi(line)) {
1481 return vt_line_bidi_convert_visual_char_index_to_logical(line, char_index);
1482 }
1483 #ifdef USE_OT_LAYOUT
1484 else if (vt_line_is_using_ot_layout(line)) {
1485 return vt_line_ot_layout_convert_visual_char_index_to_logical(line, char_index);
1486 }
1487 #endif
1488 else if (vt_line_is_using_iscii(line)) {
1489 return vt_line_iscii_convert_visual_char_index_to_logical(line, char_index);
1490 } else {
1491 return char_index;
1492 }
1493 }
1494
vt_line_is_rtl(vt_line_t * line)1495 int vt_line_is_rtl(vt_line_t *line) {
1496 if (vt_line_is_using_bidi(line)) {
1497 return vt_line_bidi_is_rtl(line);
1498 } else {
1499 return 0;
1500 }
1501 }
1502
1503 /*
1504 * It is assumed that this function is called in *visual* context.
1505 */
vt_line_copy_logical_str(vt_line_t * line,vt_char_t * dst,int beg,u_int len)1506 int vt_line_copy_logical_str(vt_line_t *line, vt_char_t *dst, int beg, /* visual position */
1507 u_int len) {
1508 if (vt_line_is_using_bidi(line)) {
1509 if (vt_line_bidi_copy_logical_str(line, dst, beg, len)) {
1510 return 1;
1511 }
1512 }
1513
1514 return vt_str_copy(dst, line->chars + beg, len);
1515 }
1516
vt_line_convert_logical_char_index_to_visual(vt_line_t * line,int char_index,u_int32_t * meet_pos_info)1517 int vt_line_convert_logical_char_index_to_visual(vt_line_t *line, int char_index,
1518 u_int32_t *meet_pos_info) {
1519 #ifdef NO_DYNAMIC_LOAD_CTL
1520 if (line->ctl_info_type) {
1521 #ifdef USE_OT_LAYOUT
1522 if (vt_line_is_using_ot_layout(line)) {
1523 char_index = vt_line_ot_layout_convert_logical_char_index_to_visual(line, char_index);
1524 } else
1525 #endif
1526 if (vt_line_is_using_bidi(line)) {
1527 #ifdef USE_FRIBIDI
1528 char_index = vt_line_bidi_convert_logical_char_index_to_visual(line, char_index,
1529 meet_pos_info);
1530 #endif
1531 } else /* if( vt_line_is_using_iscii( line)) */
1532 {
1533 #ifdef USE_IND
1534 char_index = vt_line_iscii_convert_logical_char_index_to_visual(line, char_index);
1535 #endif
1536 }
1537 }
1538
1539 return char_index;
1540 #else
1541 if (line->ctl_info_type) {
1542 #ifdef USE_OT_LAYOUT
1543 if (vt_line_is_using_ot_layout(line)) {
1544 char_index = vt_line_ot_layout_convert_logical_char_index_to_visual(line, char_index);
1545 } else
1546 #endif
1547 if (vt_line_is_using_bidi(line)) {
1548 int (*bidi_func)(vt_line_t *, int, int *);
1549
1550 if ((bidi_func = vt_load_ctl_bidi_func(VT_LINE_BIDI_CONVERT_LOGICAL_CHAR_INDEX_TO_VISUAL))) {
1551 char_index = (*bidi_func)(line, char_index, meet_pos_info);
1552 }
1553 } else /* if( vt_line_is_using_iscii( line)) */
1554 {
1555 int (*iscii_func)(vt_line_t *, int);
1556
1557 if ((iscii_func =
1558 vt_load_ctl_iscii_func(VT_LINE_ISCII_CONVERT_LOGICAL_CHAR_INDEX_TO_VISUAL))) {
1559 char_index = (*iscii_func)(line, char_index);
1560 }
1561 }
1562 }
1563
1564 return char_index;
1565 #endif
1566 }
1567
vt_line_unuse_ctl(vt_line_t * line)1568 int vt_line_unuse_ctl(vt_line_t *line) {
1569 if (line->ctl_info_type) {
1570 /* *_render() which may be called later works only if vt_line_t is really modified. */
1571 set_real_modified(line, 0, END_CHAR_INDEX(line));
1572 #ifdef USE_OT_LAYOUT
1573 if (vt_line_is_using_ot_layout(line)) {
1574 return vt_line_set_use_ot_layout(line, 0);
1575 } else
1576 #endif
1577 if (vt_line_is_using_bidi(line)) {
1578 return vt_line_set_use_bidi(line, 0);
1579 } else /* if( vt_line_is_using_iscii( line)) */
1580 {
1581 return vt_line_set_use_iscii(line, 0);
1582 }
1583 }
1584
1585 return 0;
1586 }
1587
vt_line_ctl_render(vt_line_t * line,vt_bidi_mode_t bidi_mode,const char * separators,void * term)1588 int vt_line_ctl_render(vt_line_t *line, vt_bidi_mode_t bidi_mode, const char *separators,
1589 void *term) {
1590 int ret;
1591 int (*set_use_ctl)(vt_line_t *, int);
1592
1593 if (!vt_line_is_using_ctl(line)) {
1594 if (
1595 #ifdef USE_OT_LAYOUT
1596 (!term || !vt_line_set_use_ot_layout(line, 1)) &&
1597 #endif
1598 !vt_line_set_use_bidi(line, 1) && !vt_line_set_use_iscii(line, 1)) {
1599 return 0;
1600 }
1601 }
1602
1603 if (line->ctl_info_type) {
1604 #ifdef USE_OT_LAYOUT
1605 if (vt_line_is_using_ot_layout(line)) {
1606 if (!term) {
1607 ret = -1;
1608 } else if ((ret = vt_line_ot_layout_render(line, term)) >= 0) {
1609 return ret;
1610 }
1611
1612 set_use_ctl = vt_line_set_use_ot_layout;
1613
1614 if (ret == -1) {
1615 goto render_bidi;
1616 } else /* if( ret == -2) */
1617 {
1618 goto render_iscii;
1619 }
1620 } else
1621 #endif
1622 if (vt_line_is_using_bidi(line)) {
1623 if ((ret = vt_line_bidi_render(line, bidi_mode, separators)) >= 0) {
1624 return ret;
1625 }
1626
1627 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_FRIBIDI)
1628 set_use_ctl = vt_line_set_use_bidi;
1629 #else
1630 /* Never enter here */
1631 #endif
1632
1633 if (ret == -1) {
1634 #ifdef USE_OT_LAYOUT
1635 if (!term) {
1636 return 1;
1637 }
1638
1639 goto render_ot_layout;
1640 #else
1641 return 1;
1642 #endif
1643 } else /* if( ret == -2) */
1644 {
1645 goto render_iscii;
1646 }
1647 } else /* if( vt_line_is_using_iscii( line)) */
1648 {
1649 if ((ret = vt_line_iscii_render(line)) >= 0) {
1650 return ret;
1651 }
1652
1653 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_IND)
1654 set_use_ctl = vt_line_set_use_iscii;
1655 #else
1656 /* Never enter here */
1657 #endif
1658
1659 #ifdef USE_OT_LAYOUT
1660 if (term) {
1661 goto render_ot_layout;
1662 } else
1663 #endif
1664 {
1665 goto render_bidi;
1666 }
1667 }
1668 }
1669
1670 return 0;
1671
1672 #ifdef USE_OT_LAYOUT
1673 render_ot_layout:
1674 (*set_use_ctl)(line, 0);
1675 vt_line_set_use_ot_layout(line, 1);
1676
1677 if ((ret = vt_line_ot_layout_render(line, term) != -1)) {
1678 return ret;
1679 }
1680
1681 /* Fall through */
1682 #endif
1683
1684 render_bidi:
1685 if (
1686 #if !defined(NO_DYNAMIC_LOAD_CTL)
1687 vt_load_ctl_bidi_func(VT_LINE_SET_USE_BIDI)
1688 #elif defined(USE_FRIBIDI)
1689 1
1690 #else
1691 0
1692 #endif
1693 ) {
1694 (*set_use_ctl)(line, 0);
1695 vt_line_set_use_bidi(line, 1);
1696
1697 return vt_line_bidi_render(line, bidi_mode, separators);
1698 } else {
1699 return 0;
1700 }
1701
1702 render_iscii:
1703 if (
1704 #if !defined(NO_DYNAMIC_LOAD_CTL)
1705 vt_load_ctl_iscii_func(VT_LINE_SET_USE_ISCII)
1706 #elif defined(USE_ISCII)
1707 1
1708 #else
1709 0
1710 #endif
1711 ) {
1712 (*set_use_ctl)(line, 0);
1713 vt_line_set_use_iscii(line, 1);
1714
1715 return vt_line_iscii_render(line);
1716 } else {
1717 return 0;
1718 }
1719 }
1720
vt_line_ctl_visual(vt_line_t * line)1721 int vt_line_ctl_visual(vt_line_t *line) {
1722 if (line->ctl_info_type) {
1723 #ifdef USE_OT_LAYOUT
1724 if (vt_line_is_using_ot_layout(line)) {
1725 return vt_line_ot_layout_visual(line);
1726 } else
1727 #endif
1728 if (vt_line_is_using_bidi(line)) {
1729 return vt_line_bidi_visual(line);
1730 } else /* if( vt_line_is_using_iscii( line)) */
1731 {
1732 return vt_line_iscii_visual(line);
1733 }
1734 }
1735
1736 return 0;
1737 }
1738
vt_line_ctl_logical(vt_line_t * line)1739 int vt_line_ctl_logical(vt_line_t *line) {
1740 if (line->ctl_info_type) {
1741 #ifdef USE_OT_LAYOUT
1742 if (vt_line_is_using_ot_layout(line)) {
1743 return vt_line_ot_layout_logical(line);
1744 } else
1745 #endif
1746 if (vt_line_is_using_bidi(line)) {
1747 return vt_line_bidi_logical(line);
1748 } else /* if( vt_line_is_using_iscii( line)) */
1749 {
1750 return vt_line_iscii_logical(line);
1751 }
1752 }
1753
1754 return 0;
1755 }
1756
vt_line_clear_picture(vt_line_t * line)1757 int vt_line_clear_picture(vt_line_t *line) {
1758 int count;
1759 int rmpic = 0;
1760
1761 for (count = 0; count < line->num_filled_chars; count++) {
1762 vt_char_t *ch;
1763
1764 if ((ch = vt_get_picture_char(line->chars + count))) {
1765 rmpic = 1;
1766 vt_char_copy(ch, vt_sp_ch());
1767 }
1768 }
1769
1770 return rmpic;
1771 }
1772
1773 #ifdef DEBUG
1774
vt_line_dump(vt_line_t * line)1775 void vt_line_dump(vt_line_t *line) {
1776 int count;
1777
1778 for (count = 0; count < line->num_filled_chars; count++) {
1779 vt_char_dump(line->chars + count);
1780 }
1781
1782 bl_msg_printf("\n");
1783 }
1784
1785 #endif
1786