1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "vt_drcs.h"
4 
5 #include <string.h> /* memset */
6 #include <limits.h> /* UINT_MAX */
7 #include <pobl/bl_mem.h>
8 #include <pobl/bl_str.h> /* strdup */
9 #include <pobl/bl_debug.h>
10 
11 #ifndef UINT16_MAX
12 #define UINT16_MAX ((1 << 16) - 1)
13 #endif
14 
15 /* --- static variables --- */
16 
17 static vt_drcs_t *cur_drcs;
18 
19 /* --- global functions --- */
20 
vt_drcs_select(vt_drcs_t * drcs)21 void vt_drcs_select(vt_drcs_t *drcs) {
22   cur_drcs = drcs;
23 }
24 
vt_drcs_get_glyph(ef_charset_t cs,u_char idx)25 char *vt_drcs_get_glyph(ef_charset_t cs, u_char idx) {
26   vt_drcs_font_t *font;
27 
28   /* msb can be set in vt_parser.c (e.g. ESC(I (JISX0201 kana)) */
29   if ((font = vt_drcs_get_font(cur_drcs, cs, 0)) && 0x20 <= (idx & 0x7f)) {
30 #if 0
31     /*
32      * See https://vt100.net/docs/vt510-rm/DECDLD.html
33      *
34      * Pcss: Defines the character set as a 94- or 96- character graphic set.
35      *       0 = 94-character set. (default)
36      *       1 = 96-character set.
37      * The value of Pcss changes the meaning of the Pcn (starting character) parameter above.
38      * If Pcss = 0 (94-character set)
39      * The terminal ignores any attempt to load characters into the 2/0 or 7/15 table positions.
40      *     Pcn        Specifies
41      *     1          column 2/row 1
42      *     ...
43      *     94         column 7/row 14
44      *
45      *     If Pcss = 1 (96-character set)
46      *     Pcn        Specifies
47      *     0          column 2/row 0
48      *     ...
49      *     95         column 7/row 15
50      */
51     if (IS_CS94SB(cs) && (idx == 0x20 | idx == 0x7f)) {
52       return NULL;
53     }
54 #endif
55 
56     return font->glyphs[(idx & 0x7f) - 0x20];
57   } else {
58     return NULL;
59   }
60 }
61 
vt_drcs_get_font(vt_drcs_t * drcs,ef_charset_t cs,int create)62 vt_drcs_font_t *vt_drcs_get_font(vt_drcs_t *drcs, ef_charset_t cs, int create) {
63   if (!drcs) {
64     return NULL;
65   }
66 
67   /* CS94SB(0x30)-CS94SB(0x7e) (=0x00-0x4e), CS96SB(0x30)-CS96SB(0x7e) (0x50-0x9e) */
68   if (cs > CS96SB_ID(0x7e)) {
69     return NULL;
70   }
71 
72   if (!drcs->fonts[cs]) {
73     if (!create || !(drcs->fonts[cs] = calloc(1, sizeof(vt_drcs_font_t)))) {
74       return NULL;
75     }
76   }
77 
78   return drcs->fonts[cs];
79 }
80 
vt_drcs_final(vt_drcs_t * drcs,ef_charset_t cs)81 void vt_drcs_final(vt_drcs_t *drcs, ef_charset_t cs) {
82   if (drcs) {
83     if (drcs->fonts[cs]) {
84       int idx;
85 
86       for (idx = 0; idx <= 0x5f; idx++) {
87         free(drcs->fonts[cs]->glyphs[idx]);
88       }
89 
90       free(drcs->fonts[cs]);
91       drcs->fonts[cs] = NULL;
92     }
93   }
94 }
95 
vt_drcs_final_full(vt_drcs_t * drcs)96 void vt_drcs_final_full(vt_drcs_t *drcs) {
97   ef_charset_t cs;
98 
99   for (cs = CS94SB_ID(0x30); cs <= CS96SB_ID(0x7e); cs++) {
100     vt_drcs_final(drcs, cs);
101   }
102 }
103 
vt_drcs_add_glyph(vt_drcs_font_t * font,int idx,const char * seq,u_int width,u_int height)104 void vt_drcs_add_glyph(vt_drcs_font_t *font, int idx, const char *seq, u_int width, u_int height) {
105   if (font) {
106     free(font->glyphs[idx]);
107 
108     if ((font->glyphs[idx] = malloc(2 + strlen(seq) + 1))) {
109       font->glyphs[idx][0] = width;
110       font->glyphs[idx][1] = height;
111       strcpy(font->glyphs[idx] + 2, seq);
112     }
113   }
114 }
115 
vt_drcs_add_picture(vt_drcs_font_t * font,int id,u_int offset,int beg_idx,u_int num_cols,u_int num_rows,u_int num_cols_small,u_int num_rows_small)116 void vt_drcs_add_picture(vt_drcs_font_t *font, int id, u_int offset, int beg_idx,
117                          u_int num_cols, u_int num_rows,
118                          u_int num_cols_small, u_int num_rows_small) {
119   /* 'offset > UINT32_MAX' is not necessary to check. */
120   if (num_cols > UINT16_MAX || num_rows > UINT16_MAX) {
121     return;
122   }
123 
124   if (font) {
125     font->pic_id = id;
126     font->pic_offset = offset;
127     font->pic_beg_idx = beg_idx;
128     font->pic_num_rows = num_rows;
129     font->pic_num_cols = num_cols;
130     font->pic_num_cols_small = num_cols_small;
131     font->pic_num_rows_small = num_rows_small;
132   }
133 }
134 
vt_drcs_get_picture(vt_drcs_font_t * font,int * id,int * pos,u_int ch)135 int vt_drcs_get_picture(vt_drcs_font_t *font, int *id, int *pos, u_int ch) {
136   if (font->pic_num_rows > 0) {
137     ch &= 0x7f;
138     if (ch >= 0x20 && (ch -= 0x20) >= font->pic_beg_idx) {
139       ch += font->pic_offset;
140       /* See MAKE_INLINEPIC_POS() in ui_picture.h */
141       *pos = (ch % font->pic_num_cols_small) * font->pic_num_rows +
142              (ch / font->pic_num_cols_small);
143       *id = font->pic_id;
144 
145       return 1;
146     }
147   }
148 
149   return 0;
150 }
151 
vt_convert_drcs_to_unicode_pua(ef_char_t * ch)152 int vt_convert_drcs_to_unicode_pua(ef_char_t *ch) {
153   if (vt_drcs_get_glyph(ch->cs, ch->ch[0])) {
154     if (IS_CS94SB(ch->cs)) {
155       ch->ch[2] = CS94SB_FT(ch->cs);
156       ch->ch[3] = ch->ch[0] & 0x7f;
157     } else {
158       ch->ch[2] = CS96SB_FT(ch->cs);
159       ch->ch[3] = ch->ch[0] | 0x80;
160     }
161     ch->ch[1] = 0x10;
162     ch->ch[0] = 0x00;
163     ch->cs = ISO10646_UCS4_1;
164     ch->size = 4;
165     ch->property = 0;
166 
167     return 1;
168   } else {
169     return 0;
170   }
171 }
172 
vt_convert_unicode_pua_to_drcs(ef_char_t * ch)173 int vt_convert_unicode_pua_to_drcs(ef_char_t *ch) {
174   u_char *c;
175 
176   c = ch->ch;
177 
178   if (c[1] == 0x10 && 0x30 <= c[2] && c[2] <= 0x7e && c[0] == 0x00) {
179     if (0x20 <= c[3] && c[3] <= 0x7f) {
180       ch->cs = CS94SB_ID(c[2]);
181     } else if (0xa0 <= c[3] && c[3] <= 0xff) {
182       ch->cs = CS96SB_ID(c[2]);
183     } else {
184       return 0;
185     }
186 
187     c[0] = c[3];
188     ch->size = 1;
189     ch->property = 0; /* Ignore EF_AWIDTH */
190 
191     return 1;
192   }
193 
194   return 0;
195 }
196