1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "vt_line_iscii.h"
4 
5 #include <stdio.h> /* NULL */
6 #include <pobl/bl_debug.h>
7 
8 #include "vt_iscii.h"
9 
10 /* --- global functions --- */
11 
vt_line_set_use_iscii(vt_line_t * line,int flag)12 int vt_line_set_use_iscii(vt_line_t *line, int flag) {
13   if (flag) {
14     if (vt_line_is_using_iscii(line)) {
15       return 1;
16     } else if (line->ctl_info_type != 0) {
17       return 0;
18     }
19 
20     if ((line->ctl_info.iscii = vt_iscii_new()) == NULL) {
21       return 0;
22     }
23 
24     line->ctl_info_type = VINFO_ISCII;
25   } else {
26     if (vt_line_is_using_iscii(line)) {
27       vt_iscii_destroy(line->ctl_info.iscii);
28       line->ctl_info_type = 0;
29     }
30   }
31 
32   return 1;
33 }
34 
35 /* The caller should check vt_line_is_using_iscii() in advance. */
vt_line_iscii_render(vt_line_t * line)36 int vt_line_iscii_render(vt_line_t *line /* is always visual */
37                          ) {
38   int ret;
39   int visual_mod_beg;
40 
41   /*
42    * Lower case: ASCII
43    * Upper case: ISCII
44    *    (Logical) AAA == (Visual) BBBBB
45    * => (Logical) aaa == (Visual) aaa
46    * In this case vt_line_is_cleared_to_end() returns 0, so "BB" remains on
47    * the screen unless following vt_line_set_modified().
48    */
49   visual_mod_beg = vt_line_get_beg_of_modified(line);
50   if (line->ctl_info.iscii->has_iscii) {
51     visual_mod_beg = vt_line_iscii_convert_logical_char_index_to_visual(line, visual_mod_beg);
52   }
53 
54   if (vt_line_is_real_modified(line)) {
55     if ((ret = vt_iscii(line->ctl_info.iscii, line->chars, line->num_filled_chars)) <= 0) {
56       return ret;
57     }
58 
59     if (line->ctl_info.iscii->has_iscii) {
60       int beg;
61 
62       if ((beg = vt_line_iscii_convert_logical_char_index_to_visual(
63                line, vt_line_get_beg_of_modified(line))) < visual_mod_beg) {
64         visual_mod_beg = beg;
65       }
66     }
67 
68     /*
69      * Conforming line->change_{beg|end}_col to visual mode.
70      * If this line contains ISCII chars, it should be redrawn to the end of
71      * line.
72      */
73     vt_line_set_modified(line, visual_mod_beg, line->num_chars);
74   } else {
75     vt_line_set_modified(line, visual_mod_beg, vt_line_iscii_convert_logical_char_index_to_visual(
76                                                    line, vt_line_get_end_of_modified(line)));
77   }
78 
79   return 1;
80 }
81 
82 /* The caller should check vt_line_is_using_iscii() in advance. */
vt_line_iscii_visual(vt_line_t * line)83 int vt_line_iscii_visual(vt_line_t *line) {
84   vt_char_t *src;
85   u_int src_len;
86   vt_char_t *dst;
87   u_int dst_len;
88   int dst_pos;
89   int src_pos;
90 
91   if (line->ctl_info.iscii->size == 0 || !line->ctl_info.iscii->has_iscii) {
92 #ifdef __DEBUG
93     bl_warn_printf(BL_DEBUG_TAG " Not need to visualize.\n");
94 #endif
95 
96     return 1;
97   }
98 
99   src_len = line->num_filled_chars;
100   if ((src = vt_str_alloca(src_len)) == NULL) {
101     return 0;
102   }
103   vt_str_init(src, src_len);
104   vt_str_copy(src, line->chars, src_len);
105 
106   dst_len = line->ctl_info.iscii->size;
107   if (line->num_chars < dst_len) {
108     vt_char_t *chars;
109 
110     if ((chars = vt_str_new(dst_len))) {
111       /* XXX => shrunk at vt_screen.c and vt_logical_visual_ctl.c */
112       vt_str_destroy(line->chars, line->num_chars);
113       line->chars = chars;
114       line->num_chars = dst_len;
115     } else {
116       line->ctl_info.iscii->size = dst_len = line->num_chars;
117     }
118   }
119 
120   dst = line->chars;
121 
122   src_pos = 0;
123   for (dst_pos = 0; dst_pos < dst_len; dst_pos++) {
124     if (line->ctl_info.iscii->num_chars_array[dst_pos] == 0) {
125       vt_char_copy(dst + dst_pos, vt_get_base_char(src + src_pos - 1));
126       /* NULL */
127       vt_char_set_code(dst + dst_pos, 0);
128     } else {
129       u_int count;
130 
131       vt_char_copy(dst + dst_pos, src + (src_pos++));
132 
133       for (count = 1; count < line->ctl_info.iscii->num_chars_array[dst_pos]; count++) {
134         vt_char_t *comb;
135         u_int num;
136 
137 #ifdef DEBUG
138         if (vt_char_is_comb(vt_get_base_char(src + src_pos))) {
139           bl_debug_printf(BL_DEBUG_TAG " illegal iscii\n");
140         }
141 #endif
142         vt_char_combine_simple(dst + dst_pos, vt_get_base_char(src + src_pos));
143 
144         comb = vt_get_combining_chars(src + (src_pos++), &num);
145         for (; num > 0; num--) {
146 #ifdef DEBUG
147           if (!vt_char_is_comb(comb)) {
148             bl_debug_printf(BL_DEBUG_TAG " illegal iscii\n");
149           }
150 #endif
151           vt_char_combine_simple(dst + dst_pos, comb++);
152         }
153       }
154     }
155   }
156 
157 #ifdef DEBUG
158   if (src_pos != src_len) {
159     bl_debug_printf(BL_DEBUG_TAG "vt_line_iscii_visual() failed: %d -> %d\n", src_len, src_pos);
160   }
161 #endif
162 
163   vt_str_final(src, src_len);
164 
165   line->num_filled_chars = dst_pos;
166 
167   return 1;
168 }
169 
170 /* The caller should check vt_line_is_using_iscii() in advance. */
vt_line_iscii_logical(vt_line_t * line)171 int vt_line_iscii_logical(vt_line_t *line) {
172   vt_char_t *src;
173   u_int src_len;
174   vt_char_t *dst;
175   int src_pos;
176 
177   if (line->ctl_info.iscii->size == 0 || !line->ctl_info.iscii->has_iscii) {
178 #ifdef __DEBUG
179     bl_warn_printf(BL_DEBUG_TAG " Not need to logicalize.\n");
180 #endif
181 
182     return 1;
183   }
184 
185   src_len = line->num_filled_chars;
186   if ((src = vt_str_alloca(src_len)) == NULL) {
187     return 0;
188   }
189   vt_str_init(src, src_len);
190   vt_str_copy(src, line->chars, src_len);
191   dst = line->chars;
192 
193   for (src_pos = 0; src_pos < line->ctl_info.iscii->size; src_pos++) {
194     vt_char_t *comb;
195     u_int num;
196 
197     if (line->ctl_info.iscii->num_chars_array[src_pos] == 0) {
198       continue;
199     } else if (line->ctl_info.iscii->num_chars_array[src_pos] == 1) {
200       vt_char_copy(dst, src + src_pos);
201     } else {
202       vt_char_copy(dst, vt_get_base_char(src + src_pos));
203 
204       comb = vt_get_combining_chars(src + src_pos, &num);
205       for (; num > 0; num--, comb++) {
206         if (vt_char_is_comb(comb)) {
207           vt_char_combine_simple(dst, comb);
208         } else {
209           vt_char_copy(++dst, comb);
210         }
211       }
212     }
213 
214     dst++;
215   }
216 
217   vt_str_final(src, src_len);
218 
219   line->num_filled_chars = dst - line->chars;
220 
221   return 1;
222 }
223 
224 /* The caller should check vt_line_is_using_iscii() in advance. */
vt_line_iscii_convert_logical_char_index_to_visual(vt_line_t * line,int logical_char_index)225 int vt_line_iscii_convert_logical_char_index_to_visual(vt_line_t *line, int logical_char_index) {
226   int visual_char_index;
227 
228   if (vt_line_is_empty(line)) {
229     return 0;
230   }
231 
232   if (line->ctl_info.iscii->size == 0 || !line->ctl_info.iscii->has_iscii) {
233 #ifdef __DEBUG
234     bl_debug_printf(BL_DEBUG_TAG " logical char_index is same as visual one.\n");
235 #endif
236     return logical_char_index;
237   }
238 
239   for (visual_char_index = 0; visual_char_index < line->ctl_info.iscii->size; visual_char_index++) {
240     if (logical_char_index == 0 ||
241         (logical_char_index -= line->ctl_info.iscii->num_chars_array[visual_char_index]) < 0) {
242       break;
243     }
244   }
245 
246   return visual_char_index;
247 }
248 
249 /* The caller should check vt_line_is_using_iscii() in advance. */
vt_line_iscii_convert_visual_char_index_to_logical(vt_line_t * line,int visual_char_index)250 int vt_line_iscii_convert_visual_char_index_to_logical(vt_line_t *line,
251                                                        int visual_char_index) {
252   int logical_char_index;
253   int count;
254 
255   if (vt_line_is_empty(line)) {
256     return 0;
257   }
258 
259   if (line->ctl_info.iscii->size == 0 || !line->ctl_info.iscii->has_iscii) {
260 #ifdef __DEBUG
261     bl_debug_printf(BL_DEBUG_TAG " visual char_index is same as logical one.\n");
262 #endif
263     return visual_char_index;
264   }
265 
266   if (line->ctl_info.iscii->size - 1 < visual_char_index) {
267     visual_char_index = line->ctl_info.iscii->size - 1;
268   }
269 
270   logical_char_index = 0;
271   for (count = 0; count < visual_char_index; count++) {
272     logical_char_index += line->ctl_info.iscii->num_chars_array[count];
273   }
274 
275   return logical_char_index;
276 }
277 
vt_line_iscii_need_shape(vt_line_t * line)278 int vt_line_iscii_need_shape(vt_line_t *line) {
279   return line->ctl_info.iscii->size > 0 && line->ctl_info.iscii->has_iscii;
280 }
281