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