Browse Source

* Improved ANSI importer so that it supports a lot more of what is needed

for basic vt220 emulation.
tags/v0.99.beta14
Sam Hocevar sam 18 years ago
parent
commit
1756bdf30d
1 changed files with 253 additions and 67 deletions
  1. +253
    -67
      cucul/import.c

+ 253
- 67
cucul/import.c View File

@@ -47,7 +47,7 @@ struct ansi_grcm
uint8_t fg, bg; /* ANSI-context fg/bg */
uint8_t efg, ebg; /* Effective (libcucul) fg/bg */
uint8_t dfg, dbg; /* Default fg/bg */
uint8_t bold, negative, concealed;
uint8_t bold, blink, italics, negative, concealed, underline;
};

static long int import_caca(cucul_canvas_t *, void const *, unsigned int);
@@ -348,57 +348,109 @@ static long int import_ansi(cucul_canvas_t *cv,
{
struct ansi_grcm grcm;
unsigned char const *buffer = (unsigned char const*)data;
unsigned int i, j, skip, dummy = 0;
unsigned int width = 0, height = 0, wch = 1;
uint32_t savedattr, resizeattr;
unsigned long int ch;
unsigned int i, j, skip, growx = 0, growy = 0, dummy = 0;
unsigned int width, height;
uint32_t savedattr, clearattr;
int x = 0, y = 0, save_x = 0, save_y = 0;

cucul_set_canvas_size(cv, 0, 0);
if(utf8)
{
width = cv->width;
height = cv->height;
growx = !width;
growy = !height;
x = cv->frames[cv->frame].x;
y = cv->frames[cv->frame].y;
grcm.dfg = CUCUL_DEFAULT;
grcm.dbg = CUCUL_TRANSPARENT;
}
else
{
cucul_set_canvas_size(cv, width = 80, height = 0);
growx = 0;
growy = 1;
grcm.dfg = CUCUL_LIGHTGRAY;
grcm.dbg = CUCUL_BLACK;
cucul_set_color_ansi(cv, CUCUL_LIGHTGRAY, CUCUL_BLACK);
}

resizeattr = cucul_get_attr(cv, -1, -1);
savedattr = cucul_get_attr(cv, -1, -1);
cucul_set_color_ansi(cv, grcm.dfg, grcm.dbg);
clearattr = cucul_get_attr(cv, -1, -1);

if(utf8)
cucul_set_attr(cv, savedattr);

/* FIXME: this is not right, we should store the grcm information as a
* persistent structure within the canvas. */
ansi_parse_grcm(cv, &grcm, 1, &dummy);

for(i = 0; i < size; i += skip)
{
uint32_t ch = 0;
int wch = 0;

skip = 1;

/* Wrap long lines */
if((unsigned int)x >= 80)
if(!utf8 && buffer[i] == '\x1a' && i + 7 < size
&& !memcmp(buffer + i + 1, "SAUCE00", 7))
break; /* End before SAUCE data */

else if(buffer[i] == '\r')
{
x = 0;
}

else if(buffer[i] == '\n')
{
x = 0;
y++;
}

if(buffer[i] == '\x1a' && size - i >= 8
&& !memcmp(buffer + i + 1, "SAUCE00", 7))
break; /* End before SAUCE data */
else if(buffer[i] == '\t')
{
x = (x + 7) & ~7;
}

if(buffer[i] == '\r')
continue; /* DOS sucks */
else if(buffer[i] == '\x08')
{
if(x > 0)
x--;
}

if(buffer[i] == '\n')
else if(buffer[i] == '\x1b' && buffer[i + 1] == ']'
&& buffer[i + 2] == '0' && buffer[i + 3] == ';')
{
x = 0;
y++;
continue;
for(j = i + 4; j < size; j++)
if(buffer[j] == '\x07' || buffer[j] == '\x1b'
|| buffer[j] == '\r' || buffer[j] == '\n')
break;

if(j < size && buffer[j] == '\x07')
{
char *title = malloc(j - i - 4 + 1);
memcpy(title, buffer + i + 4, j - i - 4);
title[j - i - 4] = '\0';
debug("ansi import: got display title '%s'", title);
skip += j - i;
free(title);
}
}

/* If there are not enough characters to parse the escape sequence,
* wait until the next try. We require 3. */
else if(buffer[i] == '\x1b' && i + 2 >= size)
break;

/* XXX: What the fuck is this shit? */
else if(buffer[i] == '\x1b' && buffer[i + 1] == '('
&& buffer[i + 2] == 'B')
{
skip += 2;
}

/* Interpret escape commands, as per Standard ECMA-48 "Control
* Functions for Coded Character Sets", 5.4. Control sequences. */
if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
else if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
{
unsigned int argc = 0, argv[101];
unsigned int param, inter, final;
@@ -423,7 +475,8 @@ static long int import_ansi(cucul_canvas_t *cv,
if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
break;

if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
if(i + final >= size
|| buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
break; /* Invalid Final Byte */

skip += final;
@@ -431,8 +484,9 @@ static long int import_ansi(cucul_canvas_t *cv,
/* Sanity checks */
if(param < inter && buffer[i + param] >= 0x3c)
{
fprintf(stderr, "private sequence \"^[[%.*s\"\n",
final - param + 1, buffer + i + param);
/* Private sequence, only parse what we know */
debug("ansi import: private sequence \"^[[%.*s\"",
final - param + 1, buffer + i + param);
continue; /* Private sequence, skip it entirely */
}

@@ -459,64 +513,115 @@ static long int import_ansi(cucul_canvas_t *cv,
* given in ECMA-48 8.3: Definition of control functions. */
switch(buffer[i + final])
{
case 'f': /* CUP - Cursor Position */
case 'H': /* HVP - Character And Line Position */
case 'H': /* CUP (0x48) - Cursor Position */
x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;
y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;
break;
case 'A': /* CUU - Cursor Up */
case 'A': /* CUU (0x41) - Cursor Up */
y -= argc ? argv[0] : 1;
if(y < 0)
y = 0;
break;
case 'B': /* CUD - Cursor Down */
case 'B': /* CUD (0x42) - Cursor Down */
y += argc ? argv[0] : 1;
break;
case 'C': /* CUF - Cursor Right */
case 'C': /* CUF (0x43) - Cursor Right */
x += argc ? argv[0] : 1;
break;
case 'D': /* CUB - Cursor Left */
case 'D': /* CUB (0x44) - Cursor Left */
x -= argc ? argv[0] : 1;
if(x < 0)
x = 0;
break;
case 's': /* Private (save cursor position) */
save_x = x;
save_y = y;
case 'G': /* CHA (0x47) - Cursor Character Absolute */
x = (argc && argv[0] > 0) ? argv[0] - 1 : 0;
break;
case 'u': /* Private (reload cursor position) */
x = save_x;
y = save_y;
case 'J': /* ED (0x4a) - Erase In Page */
savedattr = cucul_get_attr(cv, -1, -1);
cucul_set_attr(cv, clearattr);
if(!argc || argv[0] == 0)
{
cucul_draw_line(cv, x, y, width, y, ' ');
cucul_fill_box(cv, 0, y + 1, width - 1, height - 1, ' ');
}
else if(argv[0] == 1)
{
cucul_fill_box(cv, 0, 0, width - 1, y - 1, ' ');
cucul_draw_line(cv, 0, y, x, y, ' ');
}
else if(argv[0] == 2)
//x = y = 0;
cucul_fill_box(cv, 0, 0, width - 1, height - 1, ' ');
cucul_set_attr(cv, savedattr);
break;
case 'J': /* ED - Erase In Page */
if(argv[0] == 2)
x = y = 0;
case 'K': /* EL (0x4b) - Erase In Line */
if(!argc || argv[0] == 0)
cucul_draw_line(cv, x, y, width, y, ' ');
else if(argv[0] == 1)
cucul_draw_line(cv, 0, y, x, y, ' ');
else if(argv[0] == 2)
if((unsigned int)x < width)
cucul_draw_line(cv, x, y, width - 1, y, ' ');
//x = width;
break;
case 'K': /* EL - Erase In Line */
if(width < 80)
case 'P': /* DCH (0x50) - Delete Character */
if(!argc || argv[0] == 0)
argv[0] = 1; /* echo -ne 'foobar\r\e[0P\n' */
for(j = 0; (unsigned int)(j + argv[0]) < width; j++)
{
cucul_put_char(cv, j, y,
cucul_get_char(cv, j + argv[0], y));
cucul_put_attr(cv, j, y,
cucul_get_attr(cv, j + argv[0], y));
}
#if 0
savedattr = cucul_get_attr(cv, -1, -1);
cucul_set_attr(cv, clearattr);
for( ; (unsigned int)j < width; j++)
cucul_put_char(cv, j, y, ' ');
cucul_set_attr(cv, savedattr);
#endif
case 'X': /* ECH (0x58) - Erase Character */
if(argc && argv[0])
{
savedattr = cucul_get_attr(cv, -1, -1);
cucul_set_attr(cv, resizeattr);
cucul_set_canvas_size(cv, width = 80, height);
cucul_set_attr(cv, clearattr);
cucul_draw_line(cv, x, y, x + argv[0] - 1, y, ' ');
cucul_set_attr(cv, savedattr);
}
for(j = x; j < 80; j++)
cucul_put_char(cv, j, y, ' ');
x = 80;
case 'd': /* VPA (0x64) - Line Position Absolute */
y = (argc && argv[0] > 0) ? argv[0] - 1 : 0;
break;
case 'f': /* HVP (0x66) - Character And Line Position */
x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;
y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;
break;
case 'm': /* SGR - Select Graphic Rendition */
case 'h': /* SM (0x68) - FIXME */
debug("ansi import: set mode %i", argc ? (int)argv[0] : -1);
break;
case 'l': /* RM (0x6c) - FIXME */
debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1);
break;
case 'm': /* SGR (0x6d) - Select Graphic Rendition */
ansi_parse_grcm(cv, &grcm, argc, argv);
break;
case 's': /* Private (save cursor position) */
save_x = x;
save_y = y;
break;
case 'u': /* Private (reload cursor position) */
x = save_x;
y = save_y;
break;
default:
fprintf(stderr, "unknown command %c\n", buffer[i + final]);
debug("ansi import: unknown command \"^[[%.*s\"",
final - param + 1, buffer + i + param);
break;
}

continue;
}

/* Get the character we’re going to paste */
if(utf8)
else if(utf8)
{
unsigned int bytes;

@@ -543,39 +648,76 @@ static long int import_ansi(cucul_canvas_t *cv,
else
{
ch = cucul_cp437_to_utf32(buffer[i]);
wch = 1;
}

/* Make sure the canvas is big enough. */
if((unsigned int)x + wch > width)
/* Wrap long lines or grow horizontally */
while((unsigned int)x + wch > width)
{
savedattr = cucul_get_attr(cv, -1, -1);
cucul_set_attr(cv, resizeattr);
cucul_set_canvas_size(cv, width = x + wch, height);
cucul_set_attr(cv, savedattr);
if(growx)
{
savedattr = cucul_get_attr(cv, -1, -1);
cucul_set_attr(cv, clearattr);
cucul_set_canvas_size(cv, width = x + wch, height);
cucul_set_attr(cv, savedattr);
}
else
{
x -= width;
y++;
}
}

/* Scroll or grow vertically */
if((unsigned int)y >= height)
{
savedattr = cucul_get_attr(cv, -1, -1);
cucul_set_attr(cv, resizeattr);
cucul_set_canvas_size(cv, width, height = y + 1);
cucul_set_attr(cv, clearattr);
if(growy)
{
cucul_set_canvas_size(cv, width, height = y + 1);
}
else
{
int lines = (y - height) + 1;

for(j = 0; j + lines < height; j++)
{
memcpy(cv->attrs + j * cv->width,
cv->attrs + (j + lines) * cv->width, cv->width * 4);
memcpy(cv->chars + j * cv->width,
cv->chars + (j + lines) * cv->width, cv->width * 4);
}
cucul_fill_box(cv, 0, height - lines,
cv->width - 1, height - 1, ' ');
y -= lines;
}
cucul_set_attr(cv, savedattr);
}

/* Now paste our character */
cucul_put_char(cv, x, y, ch);
x += wch;
/* Now paste our character, if any */
if(wch)
{
cucul_put_char(cv, x, y, ch);
x += wch;
}
}

if((unsigned int)y > height)
if(growy && (unsigned int)y > height)
{
savedattr = cucul_get_attr(cv, -1, -1);
cucul_set_attr(cv, resizeattr);
cucul_set_attr(cv, clearattr);
cucul_set_canvas_size(cv, width, height = y);
cucul_set_attr(cv, savedattr);
}

return size;
cv->frames[cv->frame].x = x;
cv->frames[cv->frame].y = y;

if(utf8)
cucul_set_attr(cv, savedattr);

return i;
}

/* XXX : ANSI loader helper */
@@ -607,14 +749,23 @@ static void ansi_parse_grcm(cucul_canvas_t *cv, struct ansi_grcm *g,
case 0: /* default rendition */
g->fg = g->dfg;
g->bg = g->dbg;
g->bold = g->negative = g->concealed = 0;
g->bold = g->blink = g->italics = 0;
g->negative = g->concealed = g->underline = 0;
break;
case 1: /* bold or increased intensity */
g->bold = 1;
break;
case 2: /* faint, decreased intensity or second colour */
break;
case 3: /* italicized */
g->italics = 1;
break;
case 4: /* singly underlined */
g->underline = 1;
break;
case 5: /* slowly blinking (less then 150 per minute) */
case 6: /* rapidly blinking (150 per minute or more) */
g->blink = 1;
break;
case 7: /* negative image */
g->negative = 1;
@@ -622,20 +773,55 @@ static void ansi_parse_grcm(cucul_canvas_t *cv, struct ansi_grcm *g,
case 8: /* concealed characters */
g->concealed = 1;
break;
case 22: /* normal colour or normal intensity (neither bold nor faint) */
case 9: /* crossed-out (characters still legible but marked as to be
* deleted */
break;
case 21: /* doubly underlined */
g->underline = 1;
break;
case 22: /* normal colour or normal intensity (neither bold nor
* faint) */
g->bold = 0;
break;
case 23: /* not italicized, not fraktur */
g->italics = 0;
break;
case 24: /* not underlined (neither singly nor doubly) */
g->underline = 0;
break;
case 25: /* steady (not blinking) */
g->blink = 0;
break;
case 26: /* (reserved for proportional spacing as specified in CCITT
* Recommendation T.61) */
break;
case 27: /* positive image */
g->negative = 0;
break;
case 28: /* revealed characters */
g->concealed = 0;
break;
case 29: /* not crossed out */
break;
case 38: /* (reserved for future standardization, intended for setting
* character foreground colour as specified in ISO 8613-6
* [CCITT Recommendation T.416]) */
break;
case 39: /* default display colour (implementation-defined) */
g->fg = g->dfg;
break;
case 48: /* (reserved for future standardization, intended for setting
* character background colour as specified in ISO 8613-6
* [CCITT Recommendation T.416]) */
break;
case 49: /* default background colour (implementation-defined) */
g->bg = g->dbg;
break;
case 50: /* (reserved for cancelling the effect of the rendering
* aspect established by parameter value 26) */
break;
default:
fprintf(stderr, "unknown sgr %i\n", argv[j]);
debug("ansi import: unknown sgr %i", argv[j]);
break;
}
}


Loading…
Cancel
Save