This commit is contained in:
Stefan Seyfried
2018-01-01 22:38:35 +01:00
committed by Thilo Graf
parent 9ad4a3c8f5
commit fa0e0b1a04
47 changed files with 199240 additions and 0 deletions

View File

@@ -0,0 +1,390 @@
/* See LICENSE for licence details. */
/* function for csi sequence */
void insert_blank(struct terminal_t *term, struct parm_t *parm)
{
int i, num = sum(parm);
if (num <= 0)
num = 1;
for (i = term->cols - 1; term->cursor.x <= i; i--) {
if (term->cursor.x <= (i - num))
copy_cell(term, term->cursor.y, i, term->cursor.y, i - num);
else
erase_cell(term, term->cursor.y, i);
}
}
void curs_up(struct terminal_t *term, struct parm_t *parm)
{
int num = sum(parm);
if (num <= 0)
num = 1;
move_cursor(term, -num, 0);
}
void curs_down(struct terminal_t *term, struct parm_t *parm)
{
int num = sum(parm);
if (num <= 0)
num = 1;
move_cursor(term, num, 0);
}
void curs_forward(struct terminal_t *term, struct parm_t *parm)
{
int num = sum(parm);
if (num <= 0)
num = 1;
move_cursor(term, 0, num);
}
void curs_back(struct terminal_t *term, struct parm_t *parm)
{
int num = sum(parm);
if (num <= 0)
num = 1;
move_cursor(term, 0, -num);
}
void curs_nl(struct terminal_t *term, struct parm_t *parm)
{
int num = sum(parm);
if (num <= 0)
num = 1;
move_cursor(term, num, 0);
cr(term);
}
void curs_pl(struct terminal_t *term, struct parm_t *parm)
{
int num = sum(parm);
if (num <= 0)
num = 1;
move_cursor(term, -num, 0);
cr(term);
}
void curs_col(struct terminal_t *term, struct parm_t *parm)
{
int num;
num = (parm->argc <= 0) ? 0: dec2num(parm->argv[parm->argc - 1]) - 1;
set_cursor(term, term->cursor.y, num);
}
void curs_pos(struct terminal_t *term, struct parm_t *parm)
{
int line, col;
if (parm->argc <= 0) {
line = col = 0;
} else if (parm->argc == 2) {
line = dec2num(parm->argv[0]) - 1;
col = dec2num(parm->argv[1]) - 1;
} else {
return;
}
if (line < 0)
line = 0;
if (col < 0)
col = 0;
set_cursor(term, line, col);
}
void curs_line(struct terminal_t *term, struct parm_t *parm)
{
int num;
num = (parm->argc <= 0) ? 0: dec2num(parm->argv[parm->argc - 1]) - 1;
set_cursor(term, num, term->cursor.x);
}
void erase_display(struct terminal_t *term, struct parm_t *parm)
{
int i, j, mode;
mode = (parm->argc <= 0) ? 0: dec2num(parm->argv[parm->argc - 1]);
if (mode < 0 || 2 < mode)
return;
if (mode == 0) {
for (i = term->cursor.y; i < term->lines; i++)
for (j = 0; j < term->cols; j++)
if (i > term->cursor.y || (i == term->cursor.y && j >= term->cursor.x))
erase_cell(term, i, j);
} else if (mode == 1) {
for (i = 0; i <= term->cursor.y; i++)
for (j = 0; j < term->cols; j++)
if (i < term->cursor.y || (i == term->cursor.y && j <= term->cursor.x))
erase_cell(term, i, j);
} else if (mode == 2) {
for (i = 0; i < term->lines; i++)
for (j = 0; j < term->cols; j++)
erase_cell(term, i, j);
}
}
void erase_line(struct terminal_t *term, struct parm_t *parm)
{
int i, mode;
mode = (parm->argc <= 0) ? 0: dec2num(parm->argv[parm->argc - 1]);
if (mode < 0 || 2 < mode)
return;
if (mode == 0) {
for (i = term->cursor.x; i < term->cols; i++)
erase_cell(term, term->cursor.y, i);
} else if (mode == 1) {
for (i = 0; i <= term->cursor.x; i++)
erase_cell(term, term->cursor.y, i);
} else if (mode == 2) {
for (i = 0; i < term->cols; i++)
erase_cell(term, term->cursor.y, i);
}
}
void insert_line(struct terminal_t *term, struct parm_t *parm)
{
int num = sum(parm);
if (term->mode & MODE_ORIGIN) {
if (term->cursor.y < term->scroll.top
|| term->cursor.y > term->scroll.bottom)
return;
}
if (num <= 0)
num = 1;
scroll(term, term->cursor.y, term->scroll.bottom, -num);
}
void delete_line(struct terminal_t *term, struct parm_t *parm)
{
int num = sum(parm);
if (term->mode & MODE_ORIGIN) {
if (term->cursor.y < term->scroll.top
|| term->cursor.y > term->scroll.bottom)
return;
}
if (num <= 0)
num = 1;
scroll(term, term->cursor.y, term->scroll.bottom, num);
}
void delete_char(struct terminal_t *term, struct parm_t *parm)
{
int i, num = sum(parm);
if (num <= 0)
num = 1;
for (i = term->cursor.x; i < term->cols; i++) {
if ((i + num) < term->cols)
copy_cell(term, term->cursor.y, i, term->cursor.y, i + num);
else
erase_cell(term, term->cursor.y, i);
}
}
void erase_char(struct terminal_t *term, struct parm_t *parm)
{
int i, num = sum(parm);
if (num <= 0)
num = 1;
else if (num + term->cursor.x > term->cols)
num = term->cols - term->cursor.x;
for (i = term->cursor.x; i < term->cursor.x + num; i++)
erase_cell(term, term->cursor.y, i);
}
void set_attr(struct terminal_t *term, struct parm_t *parm)
{
int i, num;
if (parm->argc <= 0) {
term->attribute = ATTR_RESET;
term->color_pair.fg = DEFAULT_FG;
term->color_pair.bg = DEFAULT_BG;
return;
}
for (i = 0; i < parm->argc; i++) {
num = dec2num(parm->argv[i]);
if (num == 0) { /* reset all attribute and color */
term->attribute = ATTR_RESET;
term->color_pair.fg = DEFAULT_FG;
term->color_pair.bg = DEFAULT_BG;
} else if (1 <= num && num <= 7) { /* set attribute */
term->attribute |= attr_mask[num];
} else if (21 <= num && num <= 27) { /* reset attribute */
term->attribute &= ~attr_mask[num - 20];
} else if (30 <= num && num <= 37) { /* set foreground */
term->color_pair.fg = (num - 30);
} else if (num == 38) { /* set 256 color to foreground */
if ((i + 2) < parm->argc && dec2num(parm->argv[i + 1]) == 5) {
term->color_pair.fg = dec2num(parm->argv[i + 2]);
i += 2;
}
} else if (num == 39) { /* reset foreground */
term->color_pair.fg = DEFAULT_FG;
} else if (40 <= num && num <= 47) { /* set background */
term->color_pair.bg = (num - 40);
} else if (num == 48) { /* set 256 color to background */
if ((i + 2) < parm->argc && dec2num(parm->argv[i + 1]) == 5) {
term->color_pair.bg = dec2num(parm->argv[i + 2]);
i += 2;
}
} else if (num == 49) { /* reset background */
term->color_pair.bg = DEFAULT_BG;
} else if (90 <= num && num <= 97) { /* set bright foreground */
term->color_pair.fg = (num - 90) + BRIGHT_INC;
} else if (100 <= num && num <= 107) { /* set bright background */
term->color_pair.bg = (num - 100) + BRIGHT_INC;
}
}
}
void status_report(struct terminal_t *term, struct parm_t *parm)
{
int i, num;
char buf[BUFSIZE];
for (i = 0; i < parm->argc; i++) {
num = dec2num(parm->argv[i]);
if (num == 5) { /* terminal response: ready */
ewrite(term->fd, "\033[0n", 4);
} else if (num == 6) { /* cursor position report */
snprintf(buf, BUFSIZE, "\033[%d;%dR", term->cursor.y + 1, term->cursor.x + 1);
ewrite(term->fd, buf, strlen(buf));
} else if (num == 15) { /* terminal response: printer not connected */
ewrite(term->fd, "\033[?13n", 6);
}
}
}
void device_attribute(struct terminal_t *term, struct parm_t *parm)
{
/* TODO: refer VT525 DA */
(void) parm;
ewrite(term->fd, "\033[?6c", 5); /* "I am a VT102" */
}
void set_mode(struct terminal_t *term, struct parm_t *parm)
{
int i, mode;
for (i = 0; i < parm->argc; i++) {
mode = dec2num(parm->argv[i]);
if (*(term->esc.buf + 1) != '?')
continue; /* not supported */
if (mode == 6) { /* private mode */
term->mode |= MODE_ORIGIN;
set_cursor(term, 0, 0);
} else if (mode == 7) {
term->mode |= MODE_AMRIGHT;
} else if (mode == 25) {
term->mode |= MODE_CURSOR;
} else if (mode == 8901) {
term->mode |= MODE_VWBS;
}
}
}
void reset_mode(struct terminal_t *term, struct parm_t *parm)
{
int i, mode;
for (i = 0; i < parm->argc; i++) {
mode = dec2num(parm->argv[i]);
if (*(term->esc.buf + 1) != '?')
continue; /* not supported */
if (mode == 6) { /* private mode */
term->mode &= ~MODE_ORIGIN;
set_cursor(term, 0, 0);
} else if (mode == 7) {
term->mode &= ~MODE_AMRIGHT;
term->wrap_occured = false;
} else if (mode == 25) {
term->mode &= ~MODE_CURSOR;
} else if (mode == 8901) {
term->mode &= ~MODE_VWBS;
}
}
}
void set_margin(struct terminal_t *term, struct parm_t *parm)
{
int top, bottom;
if (parm->argc <= 0) { /* CSI r */
top = 0;
bottom = term->lines - 1;
} else if (parm->argc == 2) { /* CSI ; r -> use default value */
top = (parm->argv[0] == NULL) ? 0: dec2num(parm->argv[0]) - 1;
bottom = (parm->argv[1] == NULL) ? term->lines - 1: dec2num(parm->argv[1]) - 1;
} else {
return;
}
if (top < 0 || top >= term->lines)
top = 0;
if (bottom < 0 || bottom >= term->lines)
bottom = term->lines - 1;
if (top >= bottom)
return;
term->scroll.top = top;
term->scroll.bottom = bottom;
set_cursor(term, 0, 0); /* move cursor to home */
}
void clear_tabstop(struct terminal_t *term, struct parm_t *parm)
{
int i, j, num;
if (parm->argc <= 0) {
term->tabstop[term->cursor.x] = false;
} else {
for (i = 0; i < parm->argc; i++) {
num = dec2num(parm->argv[i]);
if (num == 0) {
term->tabstop[term->cursor.x] = false;
} else if (num == 3) {
for (j = 0; j < term->cols; j++)
term->tabstop[j] = false;
return;
}
}
}
}

View File

@@ -0,0 +1,586 @@
/* See LICENSE for licence details. */
/* function for dcs sequence */
enum {
RGBMAX = 255,
HUEMAX = 360,
LSMAX = 100,
};
/*
static inline void split_rgb(uint32_t color, uint8_t *r, uint8_t *g, uint8_t *b)
{
*r = bit_mask[8] & (color >> 16);
*g = bit_mask[8] & (color >> 8);
*b = bit_mask[8] & (color >> 0);
}
*/
static inline int sixel_bitmap(struct terminal_t *term, struct sixel_canvas_t *sc, uint8_t bitmap)
{
int i, offset;
//uint8_t r, g, b;
logging(DEBUG, "sixel_bitmap()\nbitmap:%.2X point(%d, %d)\n",
bitmap, sc->point.x, sc->point.y);
if (sc->point.x >= term->width || sc->point.y >= term->height)
return 1;
offset = sc->point.x * BYTES_PER_PIXEL + sc->point.y * sc->line_length;
for (i = 0; i < BITS_PER_SIXEL; i++) {
if (offset >= BYTES_PER_PIXEL * term->width * term->height)
break;
if (bitmap & (0x01 << i)) {
memcpy(sc->pixmap + offset, &sc->color_table[sc->color_index], BYTES_PER_PIXEL);
/*
split_rgb(sc->color_table[sc->color_index], &r, &g, &b);
*(sc->pixmap + offset + 0) = b;
*(sc->pixmap + offset + 1) = g;
*(sc->pixmap + offset + 2) = r;
*/
}
offset += sc->line_length;
}
sc->point.x++;
if (sc->point.x > sc->width)
sc->width = sc->point.x;
return 1;
}
static inline int sixel_repeat(struct terminal_t *term, struct sixel_canvas_t *sc, char *buf)
{
int i, count;
size_t length;
char *cp, tmp[BUFSIZE];
uint8_t bitmap;
cp = buf + 1; /* skip '!' itself */
while (isdigit(*cp)) /* skip non sixel bitmap character */
cp++;
length = (cp - buf);
strncpy(tmp, buf + 1, length - 1);
*(tmp + length - 1) = '\0';
count = dec2num(tmp);
logging(DEBUG, "sixel_repeat()\nbuf:%s length:%u\ncount:%d repeat:0x%.2X\n",
tmp, (unsigned) length, count, *cp);
if ('?' <= *cp && *cp <= '~') {
bitmap = bit_mask[BITS_PER_SIXEL] & (*cp - '?');
for (i = 0; i < count; i++)
sixel_bitmap(term, sc, bitmap);
}
return length + 1;
}
static inline int sixel_attr(struct sixel_canvas_t *sc, char *buf)
{
char *cp, tmp[BUFSIZE];
size_t length;
struct parm_t parm;
cp = buf + 1;
while (isdigit(*cp) || *cp == ';') /* skip valid params */
cp++;
length = (cp - buf);
strncpy(tmp, buf + 1, length - 1);
*(tmp + length - 1) = '\0';
reset_parm(&parm);
parse_arg(tmp, &parm, ';', isdigit);
if (parm.argc >= 4) {
sc->width = dec2num(parm.argv[2]);
sc->height = dec2num(parm.argv[3]);
}
logging(DEBUG, "sixel_attr()\nbuf:%s\nwidth:%d height:%d\n",
tmp, sc->width, sc->height);
return length;
}
static inline uint32_t hue2rgb(int n1, int n2, int hue)
{
if (hue < 0)
hue += HUEMAX;
if (hue > HUEMAX)
hue -= HUEMAX;
if (hue < (HUEMAX / 6))
return (n1 + (((n2 - n1) * hue + (HUEMAX / 12)) / (HUEMAX / 6)));
if (hue < (HUEMAX / 2))
return n2;
if (hue < ((HUEMAX * 2) / 3))
return (n1 + (((n2 - n1) * (((HUEMAX * 2) / 3) - hue) + (HUEMAX / 12)) / (HUEMAX / 6)));
else
return n1;
}
static inline uint32_t hls2rgb(int hue, int lum, int sat)
{
uint32_t r, g, b;
int magic1, magic2;
if (sat == 0) {
r = g = b = (lum * RGBMAX) / LSMAX;
} else {
if (lum <= (LSMAX / 2) )
magic2 = (lum * (LSMAX + sat) + (LSMAX / 2)) / LSMAX;
else
magic2 = lum + sat - ((lum * sat) + (LSMAX / 2)) / LSMAX;
magic1 = 2 * lum - magic2;
r = (hue2rgb(magic1, magic2, hue + (HUEMAX / 3)) * RGBMAX + (LSMAX / 2)) / LSMAX;
g = (hue2rgb(magic1, magic2, hue) * RGBMAX + (LSMAX / 2)) / LSMAX;
b = (hue2rgb(magic1, magic2, hue - (HUEMAX / 3)) * RGBMAX + (LSMAX/2)) / LSMAX;
}
return (r << 16) + (g << 8) + b;
}
static inline int sixel_color(struct sixel_canvas_t *sc, char *buf)
{
char *cp, tmp[BUFSIZE];
int index, type;
size_t length;
uint16_t v1, v2, v3, r, g, b;
uint32_t color;
struct parm_t parm;
cp = buf + 1;
while (isdigit(*cp) || *cp == ';') /* skip valid params */
cp++;
length = (cp - buf);
strncpy(tmp, buf + 1, length - 1); /* skip '#' */
*(tmp + length - 1) = '\0';
reset_parm(&parm);
parse_arg(tmp, &parm, ';', isdigit);
if (parm.argc < 1)
return length;
index = dec2num(parm.argv[0]);
if (index < 0)
index = 0;
else if (index >= COLORS)
index = COLORS - 1;
logging(DEBUG, "sixel_color()\nbuf:%s length:%u\nindex:%d\n",
tmp, (unsigned) length, index);
if (parm.argc == 1) { /* select color */
sc->color_index = index;
return length;
}
if (parm.argc != 5)
return length;
type = dec2num(parm.argv[1]);
v1 = dec2num(parm.argv[2]);
v2 = dec2num(parm.argv[3]);
v3 = dec2num(parm.argv[4]);
if (type == 1) { /* HLS */
color = hls2rgb(v1, v2, v3);
} else {
r = bit_mask[8] & (0xFF * v1 / 100);
g = bit_mask[8] & (0xFF * v2 / 100);
b = bit_mask[8] & (0xFF * v3 / 100);
color = (r << 16) | (g << 8) | b;
}
logging(DEBUG, "type:%d v1:%u v2:%u v3:%u color:0x%.8X\n",
type, v1, v2, v3, color);
sc->color_table[index] = color;
return length;
}
static inline int sixel_cr(struct sixel_canvas_t *sc)
{
logging(DEBUG, "sixel_cr()\n");
sc->point.x = 0;
return 1;
}
static inline int sixel_nl(struct sixel_canvas_t *sc)
{
logging(DEBUG, "sixel_nl()\n");
/* DECGNL moves active position to left margin
and down one line of sixels:
http://odl.sysworks.biz/disk$vaxdocdec963/decw$book/d3qsaaa1.p67.decw$book */
sc->point.y += BITS_PER_SIXEL;
sc->point.x = 0;
if (sc->point.y > sc->height)
sc->height = sc->point.y;
return 1;
}
void sixel_parse_data(struct terminal_t *term, struct sixel_canvas_t *sc, char *start_buf)
{
/*
DECDLD sixel data
'$': carriage return
'-': new line
'#': color
# Pc: select color
# Pc; Pu; Px; Py; Pz
Pc : color index (0 to 255)
Pu : color coordinate system
1: HLS (0 to 360 for Hue, 0 to 100 for others)
2: RGB (0 to 100 percent) (default)
Px : Hue / Red
Py : Lightness / Green
Pz : Saturation / Blue
'"': attr
" Pan; Pad; Ph; Pv
Pan, Pad: defines aspect ratio (Pan / Pad) (ignored)
Ph, Pv : defines vertical/horizontal size of the image
'!': repeat
! Pn ch
Pn : repeat count ([0-9]+)
ch : character to repeat ('?' to '~')
sixel bitmap:
range of ? (hex 3F) to ~ (hex 7E)
? (hex 3F) represents the binary value 00 0000.
t (hex 74) represents the binary value 11 0101.
~ (hex 7E) represents the binary value 11 1111.
*/
int size = 0;
char *cp, *end_buf;
uint8_t bitmap;
cp = start_buf;
end_buf = cp + strlen(start_buf);
while (cp < end_buf) {
if (*cp == '!') {
size = sixel_repeat(term, sc, cp);
} else if (*cp == '"') {
size = sixel_attr(sc, cp);
} else if (*cp == '#') {
size = sixel_color(sc, cp);
} else if (*cp == '$') {
size = sixel_cr(sc);
} else if (*cp == '-') {
size = sixel_nl(sc);
} else if ('?' <= *cp && *cp <= '~') {
bitmap = bit_mask[BITS_PER_SIXEL] & (*cp - '?');
size = sixel_bitmap(term, sc, bitmap);
} else if (*cp == '\0') { /* end of sixel data */
break;
} else {
size = 1;
}
cp += size;
}
logging(DEBUG, "sixel_parse_data()\nwidth:%d height:%d\n", sc->width, sc->height);
}
void reset_sixel(struct sixel_canvas_t *sc, struct color_pair_t color_pair, int width, int height)
{
extern const uint32_t color_list[]; /* global */
int i;
memset(sc->pixmap, 0, BYTES_PER_PIXEL * width * height);
sc->width = 1;
sc->height = 6;
sc->point.x = 0;
sc->point.y = 0;
sc->line_length = BYTES_PER_PIXEL * width;
sc->color_index = 0;
/* 0 - 15: use vt340 or ansi color map */
/* VT340 VT340 Default Color Map
ref: http://www.vt100.net/docs/vt3xx-gp/chapter2.html#T2-3
*/
sc->color_table[0] = 0x000000; sc->color_table[8] = 0x424242;
sc->color_table[1] = 0x3333CC; sc->color_table[9] = 0x545499;
sc->color_table[2] = 0xCC2121; sc->color_table[10] = 0x994242;
sc->color_table[3] = 0x33CC33; sc->color_table[11] = 0x549954;
sc->color_table[4] = 0xCC33CC; sc->color_table[12] = 0x995499;
sc->color_table[5] = 0x33CCCC; sc->color_table[13] = 0x549999;
sc->color_table[6] = 0xCCCC33; sc->color_table[14] = 0x999954;
sc->color_table[7] = 0x878787; sc->color_table[15] = 0xCCCCCC;
/* ANSI 16color table (but unusual order corresponding vt340 color map)
sc->color_table[0] = color_list[0]; sc->color_table[8] = color_list[8];
sc->color_table[1] = color_list[4]; sc->color_table[9] = color_list[12];
sc->color_table[2] = color_list[1]; sc->color_table[10] = color_list[9];
sc->color_table[3] = color_list[2]; sc->color_table[11] = color_list[10];
sc->color_table[4] = color_list[5]; sc->color_table[12] = color_list[13];
sc->color_table[5] = color_list[6]; sc->color_table[13] = color_list[14];
sc->color_table[6] = color_list[3]; sc->color_table[14] = color_list[11];
sc->color_table[7] = color_list[7]; sc->color_table[15] = color_list[15];
*/
/* change palette 0, because its often the same color as terminal background */
sc->color_table[0] = color_list[color_pair.fg];
/* 16 - 255: use xterm 256 color palette */
/* copy 256 color map */
for (i = 16; i < COLORS; i++)
sc->color_table[i] = color_list[i];
}
void sixel_copy2cell(struct terminal_t *term, struct sixel_canvas_t *sc)
{
int y, x, h, cols, lines;
int src_offset, dst_offset;
struct cell_t *cellp;
if (sc->height > term->height)
sc->height = term->height;
cols = my_ceil(sc->width, CELL_WIDTH);
lines = my_ceil(sc->height, CELL_HEIGHT);
if (cols + term->cursor.x > term->cols)
cols -= (cols + term->cursor.x - term->cols);
for (y = 0; y < lines; y++) {
for (x = 0; x < cols; x++) {
erase_cell(term, term->cursor.y, term->cursor.x + x);
cellp = &term->cells[term->cursor.y][term->cursor.x + x];
cellp->has_pixmap = true;
for (h = 0; h < CELL_HEIGHT; h++) {
src_offset = (y * CELL_HEIGHT + h) * sc->line_length + (CELL_WIDTH * x) * BYTES_PER_PIXEL;
dst_offset = h * CELL_WIDTH * BYTES_PER_PIXEL;
if (src_offset >= BYTES_PER_PIXEL * term->width * term->height)
break;
memcpy(cellp->pixmap + dst_offset, sc->pixmap + src_offset, CELL_WIDTH * BYTES_PER_PIXEL);
}
}
move_cursor(term, 1, 0);
//set_cursor(term, term->cursor.y + 1, term->cursor.x);
}
cr(term);
}
void sixel_parse_header(struct terminal_t *term, char *start_buf)
{
/*
sixel format
DSC P1; P2; P3; q; s...s; ST
parameters
DCS: ESC(0x1B) P (0x50) (8bit C1 character not recognized)
P1 : pixel aspect ratio (force 0, 2:1) (ignored)
P2 : background mode (ignored)
0 or 2: 0 stdands for current background color (default)
1 : 0 stands for remaining current color
P3 : horizontal grid parameter (ignored)
q : final character of sixel sequence
s : see parse_sixel_data()
ST : ESC (0x1B) '\' (0x5C) or BEL (0x07)
*/
char *cp;
struct parm_t parm;
/* replace final char of sixel header by NUL '\0' */
cp = strchr(start_buf, 'q');
*cp = '\0';
logging(DEBUG, "sixel_parse_header()\nbuf:%s\n", start_buf);
/* split header by semicolon ';' */
reset_parm(&parm);
parse_arg(start_buf, &parm, ';', isdigit);
/* set canvas parameters */
reset_sixel(&term->sixel, term->color_pair, term->width, term->height);
sixel_parse_data(term, &term->sixel, cp + 1); /* skip 'q' */
sixel_copy2cell(term, &term->sixel);
}
static inline void decdld_bitmap(struct glyph_t *glyph, uint8_t bitmap, uint8_t row, uint8_t column)
{
/*
MSB LSB (glyph_t bitmap order, padding at LSB side)
-> column
sixel bit0 ->........
sixel bit1 ->........
sixel bit2 ->....@@..
sixel bit3 ->...@..@.
sixel bit4 ->...@....
sixel bit5 ->...@....
.@@@@@..
...@....
|...@....
row |...@....
v...@....
...@....
...@....
...@....
........
........
*/
int i, height_shift, width_shift;
logging(DEBUG, "bit pattern:0x%.2X\n", bitmap);
width_shift = CELL_WIDTH - 1 - column;
if (width_shift < 0)
return;
for (i = 0; i < BITS_PER_SIXEL; i++) {
if((bitmap >> i) & 0x01) {
height_shift = row * BITS_PER_SIXEL + i;
if (height_shift < CELL_HEIGHT) {
logging(DEBUG, "height_shift:%d width_shift:%d\n", height_shift, width_shift);
glyph->bitmap[height_shift] |= bit_mask[CELL_WIDTH] & (0x01 << width_shift);
}
}
}
}
static inline void init_glyph(struct glyph_t *glyph)
{
int i;
glyph->width = 1; /* drcs glyph must be HALF */
glyph->code = 0; /* this value not used: drcs call by DRCSMMv1 */
for (i = 0; i < CELL_HEIGHT; i++)
glyph->bitmap[i] = 0;
}
void decdld_parse_data(char *start_buf, int start_char, struct glyph_t *chars)
{
/*
DECDLD sixel data
';': glyph separator
'/': line feed
sixel bitmap:
range of ? (hex 3F) to ~ (hex 7E)
? (hex 3F) represents the binary value 00 0000.
t (hex 74) represents the binary value 11 0101.
~ (hex 7E) represents the binary value 11 1111.
*/
char *cp, *end_buf;
uint8_t char_num = start_char; /* start_char == 0 means SPACE(0x20) */
uint8_t bitmap, row = 0, column = 0;
init_glyph(&chars[char_num]);
cp = start_buf;
end_buf = cp + strlen(cp);
while (cp < end_buf) {
if ('?' <= *cp && *cp <= '~') { /* sixel bitmap */
logging(DEBUG, "char_num(ten):0x%.2X\n", char_num);
/* remove offset '?' and use only 6bit */
bitmap = bit_mask[BITS_PER_SIXEL] & (*cp - '?');
decdld_bitmap(&chars[char_num], bitmap, row, column);
column++;
} else if (*cp == ';') { /* next char */
row = column = 0;
char_num++;
init_glyph(&chars[char_num]);
} else if (*cp == '/') { /* sixel nl+cr */
row++;
column = 0;
} else if (*cp == '\0') { /* end of DECDLD sequence */
break;
}
cp++;
}
}
void decdld_parse_header(struct terminal_t *term, char *start_buf)
{
/*
DECDLD format
DCS Pfn; Pcn; Pe; Pcmw; Pss; Pt; Pcmh; Pcss; f Dscs Sxbp1 ; Sxbp2 ; .. .; Sxbpn ST
parameters
DCS : ESC (0x1B) 'P' (0x50) (DCS(8bit C1 code) is not supported)
Pfn : fontset (ignored)
Pcn : start char (0 means SPACE 0x20)
Pe : erase mode
0: clear selectet charset
1: clear only redefined glyph
2: clear all drcs charset
Pcmw: max cellwidth (force CELL_WEDTH defined in glyph.h)
Pss : screen size (ignored)
Pt : defines the glyph as text or full cell or sixel (force full cell mode)
(TODO: implement sixel/text mode)
Pcmh: max cellheight (force CELL_HEIGHT defined in glyph.h)
Pcss: character set size (force: 96)
0: 94 gylphs charset
1: 96 gylphs charset
f : '{' (0x7B)
Dscs: define character set
Intermediate char: SPACE (0x20) to '/' (0x2F)
final char : '0' (0x30) to '~' (0x7E)
but allow chars between '@' (0x40) and '~' (0x7E) for DRCSMMv1
(ref: https://github.com/saitoha/drcsterm/blob/master/README.rst)
Sxbp: see parse_decdld_sixel()
ST : ESC (0x1B) '\' (0x5C) or BEL (0x07)
*/
char *cp;
int start_char, erase_mode, charset;
struct parm_t parm;
/* replace final char of DECDLD header by NUL '\0' */
cp = strchr(start_buf, '{');
*cp = '\0';
logging(DEBUG, "decdld_parse_header()\nbuf:%s\n", start_buf);
/* split header by semicolon ';' */
reset_parm(&parm);
parse_arg(start_buf, &parm, ';', isdigit);
if (parm.argc != 8) /* DECDLD header must have 8 params */
return;
/* set params */
start_char = dec2num(parm.argv[1]);
erase_mode = dec2num(parm.argv[2]);
/* parse Dscs */
cp++; /* skip final char (NUL) of DECDLD header */
while (SPACE <= *cp && *cp <= '/') /* skip intermediate char */
cp++;
if (0x40 <= *cp && *cp <= 0x7E) /* final char of Dscs must be between 0x40 to 0x7E (DRCSMMv1) */
charset = *cp - 0x40;
else
charset = 0;
logging(DEBUG, "charset(ku):0x%.2X start_char:%d erase_mode:%d\n",
charset, start_char, erase_mode);
/* reset previous glyph data */
if (erase_mode < 0 || erase_mode > 2)
erase_mode = 0;
if (erase_mode == 2) /* reset all drcs charset */
memset(term->drcs, 0, sizeof(struct glyph_t) * DRCS_CHARS);
else if (erase_mode == 0) /* reset selected drcs charset */
memset(term->drcs + GLYPHS_PER_CHARSET * charset, 0, sizeof(struct glyph_t) * DRCS_CHARS);
//if (term->drcs[charset] == NULL) /* always allcate 96 chars buffer */
//term->drcs[charset] = ecalloc(GLYPH_PER_CHARSET, sizeof(struct glyph_t));
decdld_parse_data(cp + 1, start_char, term->drcs + GLYPHS_PER_CHARSET * charset); /* skip final char */
}

View File

@@ -0,0 +1,99 @@
/* See LICENSE for licence details. */
/* function for control character */
void bs(struct terminal_t *term)
{
if (term->mode & MODE_VWBS
&& term->cursor.x - 1 >= 0
&& term->cells[term->cursor.y][term->cursor.x - 1].width == NEXT_TO_WIDE)
move_cursor(term, 0, -2);
else
move_cursor(term, 0, -1);
}
void tab(struct terminal_t *term)
{
int i;
for (i = term->cursor.x + 1; i < term->cols; i++) {
if (term->tabstop[i]) {
set_cursor(term, term->cursor.y, i);
return;
}
}
set_cursor(term, term->cursor.y, term->cols - 1);
}
void nl(struct terminal_t *term)
{
move_cursor(term, 1, 0);
}
void cr(struct terminal_t *term)
{
set_cursor(term, term->cursor.y, 0);
}
void enter_esc(struct terminal_t *term)
{
term->esc.state = STATE_ESC;
}
/* function for escape sequence */
void save_state(struct terminal_t *term)
{
term->state.mode = term->mode & MODE_ORIGIN;
term->state.cursor = term->cursor;
term->state.attribute = term->attribute;
}
void restore_state(struct terminal_t *term)
{
/* restore state */
if (term->state.mode & MODE_ORIGIN)
term->mode |= MODE_ORIGIN;
else
term->mode &= ~MODE_ORIGIN;
term->cursor = term->state.cursor;
term->attribute = term->state.attribute;
}
void crnl(struct terminal_t *term)
{
cr(term);
nl(term);
}
void set_tabstop(struct terminal_t *term)
{
term->tabstop[term->cursor.x] = true;
}
void reverse_nl(struct terminal_t *term)
{
move_cursor(term, -1, 0);
}
void identify(struct terminal_t *term)
{
ewrite(term->fd, "\033[?6c", 5); /* "I am a VT102" */
}
void enter_csi(struct terminal_t *term)
{
term->esc.state = STATE_CSI;
}
void enter_osc(struct terminal_t *term)
{
term->esc.state = STATE_OSC;
}
void enter_dcs(struct terminal_t *term)
{
term->esc.state = STATE_DCS;
}
void ris(struct terminal_t *term)
{
reset(term);
}

View File

@@ -0,0 +1,287 @@
/* See LICENSE for licence details. */
/* function for osc sequence */
int32_t parse_color1(char *seq)
{
/*
format
rgb:r/g/b
rgb:rr/gg/bb
rgb:rrr/ggg/bbb
rgb:rrrr/gggg/bbbb
*/
int i, length, value;
int32_t color;
uint32_t rgb[3];
struct parm_t parm;
reset_parm(&parm);
parse_arg(seq, &parm, '/', isalnum);
for (i = 0; i < parm.argc; i++)
logging(DEBUG, "parm.argv[%d]: %s\n", i, parm.argv[i]);
if (parm.argc != 3)
return -1;
length = strlen(parm.argv[0]);
for (i = 0; i < 3; i++) {
value = hex2num(parm.argv[i]);
logging(DEBUG, "value:%d\n", value);
if (length == 1) /* r/g/b/ */
rgb[i] = bit_mask[8] & (value * 0xFF / 0x0F);
else if (length == 2) /* rr/gg/bb */
rgb[i] = bit_mask[8] & value;
else if (length == 3) /* rrr/ggg/bbb */
rgb[i] = bit_mask[8] & (value * 0xFF / 0xFFF);
else if (length == 4) /* rrrr/gggg/bbbb */
rgb[i] = bit_mask[8] & (value * 0xFF / 0xFFFF);
else
return -1;
}
color = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
logging(DEBUG, "color:0x%.6X\n", color);
return color;
}
int32_t parse_color2(char *seq)
{
/*
format
#rgb
#rrggbb
#rrrgggbbb
#rrrrggggbbbb
*/
int i, length;
uint32_t rgb[3];
int32_t color;
char buf[BUFSIZE];
length = strlen(seq);
memset(buf, '\0', BUFSIZE);
if (length == 3) { /* rgb */
for (i = 0; i < 3; i++) {
strncpy(buf, seq + i, 1);
rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0x0F;
}
} else if (length == 6) { /* rrggbb */
for (i = 0; i < 3; i++) { /* rrggbb */
strncpy(buf, seq + i * 2, 2);
rgb[i] = bit_mask[8] & hex2num(buf);
}
} else if (length == 9) { /* rrrgggbbb */
for (i = 0; i < 3; i++) {
strncpy(buf, seq + i * 3, 3);
rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0xFFF;
}
} else if (length == 12) { /* rrrrggggbbbb */
for (i = 0; i < 3; i++) {
strncpy(buf, seq + i * 4, 4);
rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0xFFFF;
}
} else {
return -1;
}
color = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
logging(DEBUG, "color:0x%.6X\n", color);
return color;
}
void set_palette(struct terminal_t *term, void *arg)
{
/*
OSC Ps ; Pt ST
ref: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
ref: http://ttssh2.sourceforge.jp/manual/ja/about/ctrlseq.html#OSC
only recognize change color palette:
Ps: 4
Pt: c ; spec
c: color index (from 0 to 255)
spec:
rgb:r/g/b
rgb:rr/gg/bb
rgb:rrr/ggg/bbb
rgb:rrrr/gggg/bbbb
#rgb
#rrggbb
#rrrgggbbb
#rrrrggggbbbb
this rgb format is "RGB Device String Specification"
see http://xjman.dsl.gr.jp/X11R6/X11/CH06.html
Pt: c ; ?
response rgb color
OSC 4 ; c ; rgb:rr/gg/bb ST
TODO: this function only works in 32bpp mode
*/
struct parm_t *pt = (struct parm_t *) arg;
int i, argc = pt->argc, index;
int32_t color;
uint8_t rgb[3];
char **argv = pt->argv;
char buf[BUFSIZE];
if (argc != 3)
return;
index = dec2num(argv[1]);
if (index < 0 || index >= COLORS)
return;
if (strncmp(argv[2], "rgb:", 4) == 0) {
if ((color = parse_color1(argv[2] + 4)) != -1) { /* skip "rgb:" */
term->virtual_palette[index] = (uint32_t) color;
term->palette_modified = true;
}
} else if (strncmp(argv[2], "#", 1) == 0) {
if ((color = parse_color2(argv[2] + 1)) != -1) { /* skip "#" */
term->virtual_palette[index] = (uint32_t) color;
term->palette_modified = true;
}
} else if (strncmp(argv[2], "?", 1) == 0) {
for (i = 0; i < 3; i++)
rgb[i] = bit_mask[8] & (term->virtual_palette[index] >> (8 * (2 - i)));
snprintf(buf, BUFSIZE, "\033]4;%d;rgb:%.2X/%.2X/%.2X\033\\",
index, rgb[0], rgb[1], rgb[2]);
ewrite(term->fd, buf, strlen(buf));
}
}
void reset_palette(struct terminal_t *term, void *arg)
{
/*
reset color c
OSC 104 ; c ST
c: index of color
ST: BEL or ESC \
reset all color
OSC 104 ST
ST: BEL or ESC \
terminfo: oc=\E]104\E\\
*/
struct parm_t *pt = (struct parm_t *) arg;
int i, argc = pt->argc, c;
char **argv = pt->argv;
if (argc < 2) { /* reset all color palette */
for (i = 0; i < COLORS; i++)
term->virtual_palette[i] = color_list[i];
term->palette_modified = true;
} else if (argc == 2) { /* reset color_palette[c] */
c = dec2num(argv[1]);
if (0 <= c && c < COLORS) {
term->virtual_palette[c] = color_list[c];
term->palette_modified = true;
}
}
}
int isdigit_or_questionmark(int c)
{
if (isdigit(c) || c == '?')
return 1;
else
return 0;
}
void glyph_width_report(struct terminal_t *term, void *arg)
{
/*
glyph width report
* request *
OSC 8900 ; Ps ; Pw ; ? : Pf : Pt ST
Ps: reserved
Pw: width (0 or 1 or 2)
Pfrom: beginning of unicode code point
Pto: end of unicode code point
ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C)
* answer *
OSC 8900 ; Ps ; Pv ; Pw ; Pf : Pt ; Pf : Pt ; ... ST
Ps: responce code
0: ok (default)
1: recognized but not supported
2: not recognized
Pv: reserved (maybe East Asian Width Version)
Pw: width (0 or 1 or 2)
Pfrom: beginning of unicode code point
Pto: end of unicode code point
ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C)
ref
http://uobikiemukot.github.io/yaft/glyph_width_report.html
https://gist.github.com/saitoha/8767268
*/
struct parm_t *pt = (struct parm_t *) arg, sub_parm;
int i, argc = pt->argc, width, from, to, left, right, w, wcw; //reserved
char **argv = pt->argv, buf[BUFSIZE];
if (argc < 4)
return;
reset_parm(&sub_parm);
parse_arg(argv[3], &sub_parm, ':', isdigit_or_questionmark);
if (sub_parm.argc != 3 || *sub_parm.argv[0] != '?')
return;
//reserved = dec2num(argv[1]);
width = dec2num(argv[2]);
from = dec2num(sub_parm.argv[1]);
to = dec2num(sub_parm.argv[2]);
if ((width < 0) || (width > 2))
return;
/* unicode private area: plane 16 (DRCSMMv1) is always half */
if ((from < 0) || (to >= UCS2_CHARS))
return;
snprintf(buf, BUFSIZE, "\033]8900;0;0;%d;", width); /* OSC 8900 ; Ps; Pv ; Pw ; */
ewrite(term->fd, buf, strlen(buf));
left = right = -1;
for (i = from; i <= to; i++) {
wcw = wcwidth(i);
if (wcw <= 0) /* zero width */
w = 0;
else if (term->glyph[i] == NULL) /* missing glyph */
w = wcw;
else
w = term->glyph[i]->width;
if (w != width) {
if (right != -1) {
snprintf(buf, BUFSIZE, "%d:%d;", left, right);
ewrite(term->fd, buf, strlen(buf));
} else if (left != -1) {
snprintf(buf, BUFSIZE, "%d:%d;", left, left);
ewrite(term->fd, buf, strlen(buf));
}
left = right = -1;
} else {
if (left == -1)
left = i;
else
right = i;
}
}
if (right != -1) {
snprintf(buf, BUFSIZE, "%d:%d;", left, right);
ewrite(term->fd, buf, strlen(buf));
} else if (left != -1) {
snprintf(buf, BUFSIZE, "%d:%d;", left, left);
ewrite(term->fd, buf, strlen(buf));
}
ewrite(term->fd, "\033\\", 2); /* ST (ESC BACKSLASH) */
}