Project

General

Profile

Feature #6418 » ansi_escape3.diff

nobu (Nobuyoshi Nakada), 05/10/2012 07:12 PM

View differences:

w/win32/win32.c
static int NtSocketsInitialized = 0;
static st_table *socklist = NULL;
static st_table *conlist = NULL;
static char *envarea;
static char *uenvarea;
/* License: Ruby's */
struct constat {
struct {
int state, seq[5];
WORD attr;
} vt100;
};
enum {constat_init = -2, constat_esc = -1, constat_seq = 0};
/* License: Ruby's */
static int
free_conlist(st_data_t key, st_data_t val, st_data_t arg)
{
xfree((struct constat *)val);
return ST_DELETE;
}
/* License: Ruby's */
static void
constat_delete(HANDLE h)
{
if (conlist) {
st_data_t key = (st_data_t)h, val;
st_delete(conlist, &key, &val);
xfree((struct constat *)val);
}
}
/* License: Ruby's */
static void
exit_handler(void)
......
NtSocketsInitialized = 0;
}
if (conlist) {
st_foreach(conlist, free_conlist, 0);
st_free_table(conlist);
conlist = NULL;
}
if (envarea) {
FreeEnvironmentStrings(envarea);
......
/* License: Ruby's */
static struct constat *
constat_handle(HANDLE h)
{
st_data_t data;
struct constat *p;
if (!conlist) {
conlist = st_init_numtable();
}
if (st_lookup(conlist, (st_data_t)h, &data)) {
p = (struct constat *)data;
}
else {
CONSOLE_SCREEN_BUFFER_INFO csbi;
p = ALLOC(struct constat);
p->vt100.state = constat_init;
p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
if (GetConsoleScreenBufferInfo(h, &csbi)) {
p->vt100.attr = csbi.wAttributes;
}
st_insert(conlist, (st_data_t)h, (st_data_t)p);
}
return p;
}
/* License: Ruby's */
static void
constat_reset(HANDLE h)
{
st_data_t data;
struct constat *p;
if (!conlist) return;
if (!st_lookup(conlist, (st_data_t)h, &data)) return;
p = (struct constat *)data;
p->vt100.state = constat_init;
}
/* License: Ruby's */
static void
constat_apply(HANDLE handle, const struct constat *s, WCHAR w)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
const int *seq = s->vt100.seq;
int count = s->vt100.state;
int arg1 = 1;
int rev = 0;
COORD pos;
DWORD written, attr, bold;
#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
if (!GetConsoleScreenBufferInfo(handle, &csbi)) return;
if (count > 0 && seq[0] > 0) arg1 = seq[0];
switch (w) {
case L'm':
attr = csbi.wAttributes;
bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
if (count == 0) {
attr = s->vt100.attr;
}
else {
while (count-- > 0) {
switch (*seq++) {
case 0:
attr = s->vt100.attr;
rev = 0;
bold = 0;
break;
case 1:
bold |= rev ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
break;
case 4:
#ifndef COMMON_LVB_UNDERSCORE
#define COMMON_LVB_UNDERSCORE 0x8000
#endif
attr |= COMMON_LVB_UNDERSCORE;
break;
case 7:
rev = 1;
break;
case 30:
attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
break;
case 17:
case 31:
attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN) | FOREGROUND_RED;
break;
case 18:
case 32:
attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_RED) | FOREGROUND_GREEN;
break;
case 19:
case 33:
attr = attr & ~FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
break;
case 20:
case 34:
attr = attr & ~(FOREGROUND_GREEN | FOREGROUND_RED) | FOREGROUND_BLUE;
break;
case 21:
case 35:
attr = attr & ~FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
break;
case 22:
case 36:
attr = attr & ~FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
break;
case 23:
case 37:
attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
break;
case 40:
attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
case 41:
attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED;
break;
case 42:
attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_RED) | BACKGROUND_GREEN;
break;
case 43:
attr = attr & ~BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
break;
case 44:
attr = attr & ~(BACKGROUND_GREEN | BACKGROUND_RED) | BACKGROUND_BLUE;
break;
case 45:
attr = attr & ~BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
break;
case 46:
attr = attr & ~BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN;
break;
case 47:
attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
break;
}
}
}
if (rev) {
attr = attr & ~(FOREGROUND_MASK | BACKGROUND_MASK) |
((attr & FOREGROUND_MASK) << 4) |
((attr & BACKGROUND_MASK) >> 4);
}
attr |= bold;
SetConsoleTextAttribute(handle, attr);
break;
case L'A':
csbi.dwCursorPosition.Y -= arg1;
if (csbi.dwCursorPosition.Y >= 0) {
SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
}
break;
case L'B':
csbi.dwCursorPosition.Y += arg1;
if (csbi.dwCursorPosition.Y < csbi.dwSize.Y) {
SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
}
break;
case L'C':
csbi.dwCursorPosition.X += arg1;
if (csbi.dwCursorPosition.X < csbi.dwSize.X) {
SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
}
break;
case L'D':
csbi.dwCursorPosition.X -= arg1;
if (csbi.dwCursorPosition.X >= 0) {
SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
}
case L'K':
switch (arg1) {
case 0: /* erase after cursor */
FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X - csbi.dwCursorPosition.X, csbi.dwCursorPosition, &written);
break;
case 1: /* erase before cursor */
pos.X = 0;
pos.Y = csbi.dwCursorPosition.Y;
FillConsoleOutputCharacterW(handle, L' ', csbi.dwCursorPosition.X, pos, &written);
break;
case 2: /* erase entire line */
pos.X = 0;
pos.Y = csbi.dwCursorPosition.Y;
FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X, pos, &written);
break;
}
break;
}
}
static long
constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
{
const WCHAR *ptr = *ptrp;
long rest, len = *lenp;
while (len-- > 0) {
WCHAR wc = *ptr++;
if (wc == 0x1b) {
rest = *lenp - len - 1;
s->vt100.state = constat_esc;
}
else if (s->vt100.state == constat_esc && wc == L'[') {
rest = *lenp - len - 1;
if (rest > 0) --rest;
s->vt100.state = constat_seq;
s->vt100.seq[0] = 0;
}
else if (s->vt100.state >= constat_seq) {
if (wc >= L'0' && wc <= L'9') {
if (s->vt100.state < (int)numberof(s->vt100.seq)) {
int *seq = &s->vt100.seq[s->vt100.state];
*seq = (*seq * 10) + (wc - L'0');
}
}
else {
if (++s->vt100.state < (int)numberof(s->vt100.seq)) {
s->vt100.seq[s->vt100.state] = 0;
}
else {
s->vt100.state = (int)numberof(s->vt100.seq);
}
if (wc != L';') {
constat_apply(h, s, wc);
s->vt100.state = constat_init;
}
}
rest = 0;
}
else {
continue;
}
*ptrp = ptr;
*lenp = len;
return rest;
}
len = *lenp;
*ptrp = ptr;
*lenp = 0;
return len;
}
/* License: Ruby's */
int
rb_w32_close(int fd)
......
_set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
socklist_delete(&sock, NULL);
constat_delete((HANDLE)sock);
_close(fd);
errno = save_errno;
......
/* get rid of console reading bug */
if (isconsole) {
constat_reset((HANDLE)_osfhnd(fd));
if (start)
len = 1;
......
DWORD dwMode, reslen;
VALUE str = strarg;
rb_encoding *utf16 = rb_enc_find("UTF-16LE");
const WCHAR *ptr, *next;
struct constat *s;
long len;
if (disable) return -1L;
......
return -1L;
str = rb_str_encode(str, rb_enc_from_encoding(rb_enc_find("UTF-16LE")),
str = rb_str_encode(str, rb_enc_from_encoding(utf16),
ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil);
if (!WriteConsoleW(handle, (LPWSTR)RSTRING_PTR(str), RSTRING_LEN(str)/2,
&reslen, NULL)) {
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
disable = TRUE;
return -1L;
ptr = (const WCHAR *)RSTRING_PTR(str);
len = RSTRING_LEN(str) / sizeof(WCHAR);
s = constat_handle(handle);
while (len > 0) {
long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
if (curlen > 0) {
if (!WriteConsoleW(handle, ptr, curlen, &reslen, NULL)) {
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
disable = TRUE;
return -1L;
}
}
ptr = next;
}
RB_GC_GUARD(str);
return (long)reslen;
}
(3-3/4)