1 /*
2  * Copyright (C) 2014 haru <uobikiemukot at gmail dot com>
3  * Copyright (C) 2014 Hayaki Saito <user@zuse.jp>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /* function for dcs sequence */
20 
21 
22 #include "config.h"
23 
24 #include "yaft.h"
25 #include "util.h"
26 #include "terminal.h"
27 #include "function.h"
28 #include "dcs.h"
29 
30 #include <stdio.h>
31 #if HAVE_CTYPE_H
32 # include <ctype.h>
33 #endif
34 #if HAVE_STDLIB_H
35 # include <stdlib.h>
36 #endif
37 #if HAVE_STRING_H
38 # include <string.h>
39 #endif
40 
41 #if !defined(HAVE_MEMCPY)
42 # define memcpy(d, s, n) (bcopy ((s), (d), (n)))
43 #endif
44 
45 enum {
46     RGBMAX = 255,
47     HUEMAX = 360,
48     LSMAX  = 100,
49 };
50 
sixel_bitmap(struct terminal * term,struct sixel_canvas_t * sc,uint8_t bitmap)51 static int sixel_bitmap(struct terminal *term, struct sixel_canvas_t *sc, uint8_t bitmap)
52 {
53     int i, offset;
54 
55     if (DEBUG)
56         fprintf(stderr, "sixel_bitmap()\nbitmap:%.2X point(%d, %d)\n",
57             bitmap, sc->point.x, sc->point.y);
58 
59     if (sc->point.x >= term->width || sc->point.y >= term->height)
60         return 1;
61 
62     offset = sc->point.x * BYTES_PER_PIXEL + sc->point.y * sc->line_length;
63 
64     for (i = 0; i < BITS_PER_SIXEL; i++) {
65         if (offset >= BYTES_PER_PIXEL * term->width * term->height)
66             break;
67 
68         if (bitmap & (0x01 << i))
69             memcpy(sc->bitmap + offset, &sc->color_table[sc->color_index], BYTES_PER_PIXEL);
70 
71         offset += sc->line_length;
72     }
73     sc->point.x++;
74 
75     if (sc->point.x > sc->width)
76         sc->width = sc->point.x;
77 
78     return 1;
79 }
80 
sixel_repeat(struct terminal * term,struct sixel_canvas_t * sc,char * buf)81 static int sixel_repeat(struct terminal *term, struct sixel_canvas_t *sc, char *buf)
82 {
83     int i, count;
84     size_t length;
85     char *cp, tmp[BUFSIZE];
86     uint8_t bitmap;
87 
88     cp = buf + 1; /* skip '!' itself */
89     while (isdigit(*cp)) /* skip non sixel bitmap character */
90         cp++;
91 
92     length = (cp - buf);
93     strncpy(tmp, buf + 1, length - 1);
94     *(tmp + length - 1) = '\0';
95 
96     count = dec2num(tmp);
97 
98     if (DEBUG)
99         fprintf(stderr, "sixel_repeat()\nbuf:%s length:%u\ncount:%d repeat:0x%.2X\n",
100             tmp, (unsigned) length, count, *cp);
101 
102     if ('?' <= *cp && *cp <= '~') {
103         bitmap = bit_mask[BITS_PER_SIXEL] & (*cp - '?');
104         for (i = 0; i < count; i++)
105             sixel_bitmap(term, sc, bitmap);
106     }
107 
108     return length + 1;
109 }
110 
sixel_attr(struct sixel_canvas_t * sc,char * buf)111 static int sixel_attr(struct sixel_canvas_t *sc, char *buf)
112 {
113     char *cp, tmp[BUFSIZE];
114     size_t length;
115     struct parm_t parm;
116 
117     cp = buf + 1;
118     while (isdigit(*cp) || *cp == ';') /* skip valid params */
119         cp++;
120 
121     length = (cp - buf);
122     strncpy(tmp, buf + 1, length - 1);
123     *(tmp + length - 1) = '\0';
124 
125     reset_parm(&parm);
126     parse_arg(tmp, &parm, ';', isdigit);
127 
128     if (parm.argc >= 4) {
129         sc->width  = dec2num(parm.argv[2]);
130         sc->height = dec2num(parm.argv[3]);
131     }
132 
133     if (DEBUG)
134         fprintf(stderr, "sixel_attr()\nbuf:%s\nwidth:%d height:%d\n",
135             tmp, sc->width, sc->height);
136 
137     return length;
138 }
139 
hue2rgb(int n1,int n2,int hue)140 static uint32_t hue2rgb(int n1, int n2, int hue)
141 {
142     if (hue < 0)
143         hue += HUEMAX;
144 
145     if (hue > HUEMAX)
146         hue -= HUEMAX;
147 
148     if (hue < (HUEMAX / 6))
149         return (n1 + (((n2 - n1) * hue + (HUEMAX / 12)) / (HUEMAX / 6)));
150     if (hue < (HUEMAX / 2))
151         return n2;
152     if (hue < ((HUEMAX * 2) / 3))
153         return (n1 + (((n2 - n1) * (((HUEMAX * 2) / 3) - hue) + (HUEMAX / 12)) / (HUEMAX / 6)));
154     else
155         return n1;
156 }
157 
hls2rgb(int hue,int lum,int sat)158 static uint32_t hls2rgb(int hue, int lum, int sat)
159 {
160     uint32_t r, g, b;
161     int magic1, magic2;
162 
163     if (sat == 0) {
164         r = g = b = (lum * RGBMAX) / LSMAX;
165     }
166     else {
167         if (lum <= (LSMAX / 2) )
168             magic2 = (lum * (LSMAX + sat) + (LSMAX / 2)) / LSMAX;
169         else
170             magic2 = lum + sat - ((lum * sat) + (LSMAX / 2)) / LSMAX;
171         magic1 = 2 * lum - magic2;
172 
173         r = (hue2rgb(magic1, magic2, hue + (HUEMAX / 3)) * RGBMAX + (LSMAX / 2)) / LSMAX;
174         g = (hue2rgb(magic1, magic2, hue) * RGBMAX + (LSMAX / 2)) / LSMAX;
175         b = (hue2rgb(magic1, magic2, hue - (HUEMAX / 3)) * RGBMAX + (LSMAX/2)) / LSMAX;
176     }
177     return (r << 16) + (g << 8) + b;
178 }
179 
sixel_color(struct sixel_canvas_t * sc,char * buf)180 static int sixel_color(struct sixel_canvas_t *sc, char *buf)
181 {
182     char *cp, tmp[BUFSIZE];
183     int index, type;
184     size_t length;
185     uint16_t v1, v2, v3, r, g, b;
186     uint32_t color;
187     struct parm_t parm;
188 
189     cp = buf + 1;
190     while (isdigit(*cp) || *cp == ';') /* skip valid params */
191         cp++;
192 
193     length = (cp - buf);
194     strncpy(tmp, buf + 1, length - 1); /* skip '#' */
195     *(tmp + length - 1) = '\0';
196 
197     reset_parm(&parm);
198     parse_arg(tmp, &parm, ';', isdigit);
199 
200     if (parm.argc < 1)
201         return length;
202 
203     index = dec2num(parm.argv[0]);
204     if (index < 0)
205         index = 0;
206     else if (index >= COLORS)
207         index = COLORS - 1;
208 
209     if (DEBUG)
210         fprintf(stderr, "sixel_color()\nbuf:%s length:%u\nindex:%d\n",
211             tmp, (unsigned) length, index);
212 
213     if (parm.argc == 1) { /* select color */
214         sc->color_index = index;
215         return length;
216     }
217 
218     if (parm.argc != 5)
219         return length;
220 
221     type  = dec2num(parm.argv[1]);
222     v1    = dec2num(parm.argv[2]);
223     v2    = dec2num(parm.argv[3]);
224     v3    = dec2num(parm.argv[4]);
225 
226     if (type == 1) /* HLS */
227         color = hls2rgb(v1, v2, v3);
228     else {
229         r = bit_mask[8] & (0xFF * v1 / 100);
230         g = bit_mask[8] & (0xFF * v2 / 100);
231         b = bit_mask[8] & (0xFF * v3 / 100);
232         color = (r << 16) | (g << 8) | b;
233     }
234 
235     if (DEBUG)
236         fprintf(stderr, "type:%d v1:%u v2:%u v3:%u color:0x%.8X\n",
237             type, v1, v2, v3, color);
238 
239     sc->color_table[index] = color;
240 
241     return length;
242 }
243 
sixel_cr(struct sixel_canvas_t * sc)244 static int sixel_cr(struct sixel_canvas_t *sc)
245 {
246     if (DEBUG)
247         fprintf(stderr, "sixel_cr()\n");
248 
249     sc->point.x = 0;
250 
251     return 1;
252 }
253 
sixel_nl(struct sixel_canvas_t * sc)254 static int sixel_nl(struct sixel_canvas_t *sc)
255 {
256     if (DEBUG)
257         fprintf(stderr, "sixel_nl()\n");
258 
259     /* DECGNL moves active position to left margin
260         and down one line of sixels:
261         http://odl.sysworks.biz/disk$vaxdocdec963/decw$book/d3qsaaa1.p67.decw$book */
262     sc->point.y += BITS_PER_SIXEL;
263     sc->point.x = 0;
264 
265     if (sc->point.y > sc->height)
266         sc->height = sc->point.y;
267 
268     return 1;
269 }
270 
sixel_parse_data(struct terminal * term,struct sixel_canvas_t * sc,char * start_buf)271 void sixel_parse_data(struct terminal *term, struct sixel_canvas_t *sc, char *start_buf)
272 {
273     /*
274     DECDLD sixel data
275         '$': carriage return
276         '-': new line
277         '#': color
278             # Pc: select color
279             # Pc; Pu; Px; Py; Pz
280                 Pc : color index (0 to 255)
281                 Pu : color coordinate system
282                     1: HLS (0 to 360 for Hue, 0 to 100 for others)
283                     2: RGB (0 to 100 percent) (default)
284                 Px : Hue        / Red
285                 Py : Lightness  / Green
286                 Pz : Saturation / Blue
287         '"': attr
288             " Pan; Pad; Ph; Pv
289                 Pan, Pad: defines aspect ratio (Pan / Pad) (ignored)
290                 Ph, Pv  : defines vertical/horizontal size of the image
291         '!': repeat
292             ! Pn ch
293                 Pn : repeat count ([0-9]+)
294                 ch : character to repeat ('?' to '~')
295         sixel bitmap:
296             range of ? (hex 3F) to ~ (hex 7E)
297             ? (hex 3F) represents the binary value 00 0000.
298             t (hex 74) represents the binary value 11 0101.
299             ~ (hex 7E) represents the binary value 11 1111.
300     */
301     int size = 0;
302     char *cp;
303     uint8_t bitmap;
304 
305     cp = start_buf;
306 
307     while (1) {
308         if ('?' <= *cp && *cp <= '~')  {
309             bitmap =  bit_mask[BITS_PER_SIXEL] & (*cp - '?');
310             size = sixel_bitmap(term, sc, bitmap);
311         } else if (*cp == '!')
312             size = sixel_repeat(term, sc, cp);
313         else if (*cp == '"')
314             size = sixel_attr(sc, cp);
315         else if (*cp == '#')
316             size = sixel_color(sc, cp);
317         else if (*cp == '$')
318             size = sixel_cr(sc);
319         else if (*cp == '-')
320             size = sixel_nl(sc);
321         else if (*cp == '\0') /* end of sixel data */
322             break;
323         else
324             size = 1;
325         cp += size;
326     }
327 
328     if (DEBUG)
329         fprintf(stderr, "sixel_parse_data()\nwidth:%d height:%d\n", sc->width, sc->height);
330 }
331 
reset_sixel(struct sixel_canvas_t * sc,struct color_pair_t color_pair,int width,int height)332 void reset_sixel(struct sixel_canvas_t *sc, struct color_pair_t color_pair, int width, int height)
333 {
334     extern const uint32_t color_list[]; /* global */
335     int i;
336 
337     memset(sc->bitmap, 0, BYTES_PER_PIXEL * width * height);
338 
339     sc->width   = 1;
340     sc->height  = 6;
341     sc->point.x    = 0;
342     sc->point.y = 0;
343     sc->line_length = BYTES_PER_PIXEL * width;
344     sc->color_index = 0;
345 
346     /* 0 - 15: use vt340 or ansi color map */
347     /* VT340 VT340 Default Color Map
348         ref: http://www.vt100.net/docs/vt3xx-gp/chapter2.html#T2-3
349     */
350     sc->color_table[0] = 0x000000; sc->color_table[8]  = 0x424242;
351     sc->color_table[1] = 0x3333CC; sc->color_table[9]  = 0x545499;
352     sc->color_table[2] = 0xCC2121; sc->color_table[10] = 0x994242;
353     sc->color_table[3] = 0x33CC33; sc->color_table[11] = 0x549954;
354     sc->color_table[4] = 0xCC33CC; sc->color_table[12] = 0x995499;
355     sc->color_table[5] = 0x33CCCC; sc->color_table[13] = 0x549999;
356     sc->color_table[6] = 0xCCCC33; sc->color_table[14] = 0x999954;
357     sc->color_table[7] = 0x878787; sc->color_table[15] = 0xCCCCCC;
358 
359     /* ANSI 16color table (but unusual order corresponding vt340 color map)
360     sc->color_table[0] = color_list[0]; sc->color_table[8]  = color_list[8];
361     sc->color_table[1] = color_list[4]; sc->color_table[9]  = color_list[12];
362     sc->color_table[2] = color_list[1]; sc->color_table[10] = color_list[9];
363     sc->color_table[3] = color_list[2]; sc->color_table[11] = color_list[10];
364     sc->color_table[4] = color_list[5]; sc->color_table[12] = color_list[13];
365     sc->color_table[5] = color_list[6]; sc->color_table[13] = color_list[14];
366     sc->color_table[6] = color_list[3]; sc->color_table[14] = color_list[11];
367     sc->color_table[7] = color_list[7]; sc->color_table[15] = color_list[15];
368     */
369     /* change palette 0, because its often the same color as terminal background */
370     sc->color_table[0] = color_list[color_pair.fg];
371 
372     /* 16 - 255: use xterm 256 color palette */
373     /* copy 256 color map */
374     for (i = 16; i < COLORS; i++)
375         sc->color_table[i] = color_list[i];
376 }
377 
sixel_copy2cell(struct terminal * term,struct sixel_canvas_t * sc)378 void sixel_copy2cell(struct terminal *term, struct sixel_canvas_t *sc)
379 {
380     int y, x, h, cols, lines;
381     int src_offset, dst_offset;
382     struct cell_t *cellp;
383 
384     if (sc->height > term->height)
385         sc->height = term->height;
386 
387     cols  = my_ceil(sc->width, CELL_WIDTH);
388     lines = my_ceil(sc->height, CELL_HEIGHT);
389 
390     if (cols + term->cursor.x > term->cols)
391         cols -= (cols + term->cursor.x - term->cols);
392 
393     for (y = 0; y < lines; y++) {
394         for (x = 0; x < cols; x++) {
395             erase_cell(term, term->cursor.y, term->cursor.x + x);
396             cellp = &term->cells[term->cursor.y * term->cols + (term->cursor.x + x)];
397             cellp->has_bitmap = true;
398             for (h = 0; h < CELL_HEIGHT; h++) {
399                 src_offset = (y * CELL_HEIGHT + h) * sc->line_length + (CELL_WIDTH * x) * BYTES_PER_PIXEL;
400                 dst_offset = h * CELL_WIDTH * BYTES_PER_PIXEL;
401                 if (src_offset >= BYTES_PER_PIXEL * term->width * term->height)
402                     break;
403                 memcpy(cellp->bitmap + dst_offset, sc->bitmap + src_offset, CELL_WIDTH * BYTES_PER_PIXEL);
404             }
405         }
406         move_cursor(term, 1, 0);
407     }
408     cr(term);
409 }
410 
sixel_parse_header(struct terminal * term,char * start_buf)411 void sixel_parse_header(struct terminal *term, char *start_buf)
412 {
413     /*
414     sixel format
415         DSC P1; P2; P3; q; s...s; ST
416     parameters
417         DCS: ESC(0x1B) P (0x50) (8bit C1 character not recognized)
418         P1 : pixel aspect ratio (force 0, 2:1) (ignored)
419         P2 : background mode (ignored)
420             0 or 2: 0 stdands for current background color (default)
421             1     : 0 stands for remaining current color
422         P3 : horizontal grid parameter (ignored)
423         q  : final character of sixel sequence
424         s  : see parse_sixel_data()
425         ST : ESC (0x1B) '\' (0x5C) or BEL (0x07)
426     */
427     char *cp;
428     struct parm_t parm;
429 
430     /* replace final char of sixel header by NUL '\0' */
431     cp = strchr(start_buf, 'q');
432     *cp = '\0';
433 
434     if (DEBUG)
435         fprintf(stderr, "sixel_parse_header()\nbuf:%s\n", start_buf);
436 
437     /* split header by semicolon ';' */
438     reset_parm(&parm);
439     parse_arg(start_buf, &parm, ';', isdigit);
440 
441     /* set canvas parameters */
442     reset_sixel(&term->sixel, term->color_pair, term->width, term->height);
443     sixel_parse_data(term, &term->sixel, cp + 1); /* skip 'q' */
444     sixel_copy2cell(term, &term->sixel);
445 }
446 
decdld_bitmap(struct glyph_t * glyph,uint8_t bitmap,uint8_t row,uint8_t column)447 static void decdld_bitmap(struct glyph_t *glyph, uint8_t bitmap, uint8_t row, uint8_t column)
448 {
449     /*
450               MSB        LSB (glyph_t bitmap order, padding at LSB side)
451                   -> column
452     sixel bit0 ->........
453     sixel bit1 ->........
454     sixel bit2 ->....@@..
455     sixel bit3 ->...@..@.
456     sixel bit4 ->...@....
457     sixel bit5 ->...@....
458                  .@@@@@..
459                  ...@....
460                 |...@....
461             row |...@....
462                 v...@....
463                  ...@....
464                  ...@....
465                  ...@....
466                  ........
467                  ........
468     */
469     int i, height_shift, width_shift;
470 
471     if (DEBUG)
472         fprintf(stderr, "bit pattern:0x%.2X\n", bitmap);
473 
474     width_shift = CELL_WIDTH - 1 - column;
475     if (width_shift < 0)
476         return;
477 
478     for (i = 0; i < BITS_PER_SIXEL; i++) {
479         if((bitmap >> i) & 0x01) {
480             height_shift = row * BITS_PER_SIXEL + i;
481 
482             if (height_shift < CELL_HEIGHT) {
483                 if (DEBUG)
484                     fprintf(stderr, "height_shift:%d width_shift:%d\n", height_shift, width_shift);
485                 glyph->bitmap[height_shift] |= bit_mask[CELL_WIDTH] & (0x01 << width_shift);
486             }
487         }
488     }
489 }
490 
init_glyph(struct glyph_t * glyph)491 static void init_glyph(struct glyph_t *glyph)
492 {
493     int i;
494 
495     glyph->width = 1; /* drcs glyph must be HALF */
496     glyph->code = 0;  /* this value not used: drcs call by DRCSMMv1 */
497 
498     for (i = 0; i < CELL_HEIGHT; i++)
499         glyph->bitmap[i] = 0;
500 }
501 
decdld_parse_data(char * start_buf,int start_char,struct glyph_t * chars)502 void decdld_parse_data(char *start_buf, int start_char, struct glyph_t *chars)
503 {
504     /*
505     DECDLD sixel data
506         ';': glyph separator
507         '/': line feed
508         sixel bitmap:
509             range of ? (hex 3F) to ~ (hex 7E)
510             ? (hex 3F) represents the binary value 00 0000.
511             t (hex 74) represents the binary value 11 0101.
512             ~ (hex 7E) represents the binary value 11 1111.
513     */
514     char *cp, *end_buf;
515     uint8_t char_num = start_char; /* start_char == 0 means SPACE(0x20) */
516     uint8_t bitmap, row = 0, column = 0;
517 
518     init_glyph(&chars[char_num]);
519     cp      = start_buf;
520     end_buf = cp + strlen(cp);
521 
522     while (cp < end_buf) {
523         if ('?' <= *cp && *cp <= '~') { /* sixel bitmap */
524             if (DEBUG)
525                 fprintf(stderr, "char_num(ten):0x%.2X\n", char_num);
526             /* remove offset '?' and use only 6bit */
527             bitmap = bit_mask[BITS_PER_SIXEL] & (*cp - '?');
528             decdld_bitmap(&chars[char_num], bitmap, row, column);
529             column++;
530         }
531         else if (*cp == ';') { /* next char */
532             row = column = 0;
533             char_num++;
534             init_glyph(&chars[char_num]);
535         }
536         else if (*cp == '/') { /* sixel nl+cr */
537             row++;
538             column = 0;
539         }
540         else if (*cp == '\0')  /* end of DECDLD sequence */
541             break;
542         cp++;
543     }
544 }
545 
decdld_parse_header(struct terminal * term,char * start_buf)546 void decdld_parse_header(struct terminal *term, char *start_buf)
547 {
548     /*
549     DECDLD format
550         DCS Pfn; Pcn; Pe; Pcmw; Pss; Pt; Pcmh; Pcss; f Dscs Sxbp1 ; Sxbp2 ; .. .; Sxbpn ST
551     parameters
552         DCS : ESC (0x1B) 'P' (0x50) (DCS(8bit C1 code) is not supported)
553         Pfn : fontset (ignored)
554         Pcn : start char (0 means SPACE 0x20)
555         Pe  : erase mode
556                 0: clear selectet charset
557                 1: clear only redefined glyph
558                 2: clear all drcs charset
559         Pcmw: max cellwidth (force CELL_WEDTH defined in glyph.h)
560         Pss : screen size (ignored)
561         Pt  : defines the glyph as text or full cell or sixel (force full cell mode)
562               (TODO: implement sixel/text mode)
563         Pcmh: max cellheight (force CELL_HEIGHT defined in glyph.h)
564         Pcss: character set size (force: 96)
565                 0: 94 gylphs charset
566                 1: 96 gylphs charset
567         f   : '{' (0x7B)
568         Dscs: define character set
569                 Intermediate char: SPACE (0x20) to '/' (0x2F)
570                 final char       : '0' (0x30) to '~' (0x7E)
571                                     but allow chars between '@' (0x40) and '~' (0x7E) for DRCSMMv1
572                                     (ref: https://github.com/saitoha/drcsterm/blob/master/README.rst)
573         Sxbp: see parse_decdld_sixel()
574         ST  : ESC (0x1B) '\' (0x5C) or BEL (0x07)
575     */
576     char *cp;
577     int i, start_char, erase_mode, charset;
578     struct parm_t parm;
579 
580     /* replace final char of DECDLD header by NUL '\0' */
581     cp = strchr(start_buf, '{');
582     *cp = '\0';
583 
584     if (DEBUG)
585         fprintf(stderr, "decdld_parse_header()\nbuf:%s\n", start_buf);
586 
587     /* split header by semicolon ';' */
588     reset_parm(&parm);
589     parse_arg(start_buf, &parm, ';', isdigit);
590 
591     if (parm.argc != 8) /* DECDLD header must have 8 params */
592         return;
593 
594     /* set params */
595     start_char = dec2num(parm.argv[1]);
596     erase_mode = dec2num(parm.argv[2]);
597 
598     /* parse Dscs */
599     cp++; /* skip final char (NUL) of DECDLD header */
600     while (SPACE <= *cp && *cp <= '/') /* skip intermediate char */
601         cp++;
602 
603     if (0x40 <= *cp && *cp <= 0x7E) /* final char of Dscs must be between 0x40 to 0x7E (DRCSMMv1) */
604         charset = *cp - 0x40;
605     else
606         charset = 0;
607 
608     if (DEBUG)
609         fprintf(stderr, "charset(ku):0x%.2X start_char:%d erase_mode:%d\n",
610             charset, start_char, erase_mode);
611 
612     /* reset previous glyph data */
613     if (erase_mode < 0 || erase_mode > 2)
614         erase_mode = 0;
615 
616     if (erase_mode == 2) {      /* reset all drcs charset */
617         for (i = 0; i < DRCS_CHARSETS; i++) {
618             if (term->drcs[i] != NULL) {
619                 free(term->drcs[i]);
620                 term->drcs[i] = NULL;
621             }
622         }
623     }
624     else if (erase_mode == 0) { /* reset selected drcs charset */
625         if (term->drcs[charset] != NULL) {
626             free(term->drcs[charset]);
627             term->drcs[charset] = NULL;
628         }
629     }
630 
631     if (term->drcs[charset] == NULL) /* always allcate 96 chars buffer */
632         term->drcs[charset] = ecalloc(GLYPH_PER_CHARSET, sizeof(struct glyph_t));
633 
634     decdld_parse_data(cp + 1, start_char, term->drcs[charset]); /* skil final char */
635 }
636 
637 /* emacs, -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
638 /* vim: set expandtab ts=4 : */
639 /* EOF */
640