Feature #6418 » ansi_escape3.diff
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;
|
||
}
|