Project

General

Profile

Feature #6418 ยป ansi_escape3.diff

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

View differences:

w/win32/win32.c
630 630
static int NtSocketsInitialized = 0;
631 631
static st_table *socklist = NULL;
632
static st_table *conlist = NULL;
632 633
static char *envarea;
633 634
static char *uenvarea;
634 635

  
635 636
/* License: Ruby's */
637
struct constat {
638
    struct {
639
	int state, seq[5];
640
	WORD attr;
641
    } vt100;
642
};
643
enum {constat_init = -2, constat_esc = -1, constat_seq = 0};
644

  
645
/* License: Ruby's */
646
static int
647
free_conlist(st_data_t key, st_data_t val, st_data_t arg)
648
{
649
    xfree((struct constat *)val);
650
    return ST_DELETE;
651
}
652

  
653
/* License: Ruby's */
654
static void
655
constat_delete(HANDLE h)
656
{
657
    if (conlist) {
658
	st_data_t key = (st_data_t)h, val;
659
	st_delete(conlist, &key, &val);
660
	xfree((struct constat *)val);
661
    }
662
}
663

  
664
/* License: Ruby's */
636 665
static void
637 666
exit_handler(void)
......
646 675
	NtSocketsInitialized = 0;
647 676
    }
677
    if (conlist) {
678
	st_foreach(conlist, free_conlist, 0);
679
	st_free_table(conlist);
680
	conlist = NULL;
681
    }
648 682
    if (envarea) {
649 683
	FreeEnvironmentStrings(envarea);
......
5529 5563

  
5530 5564
/* License: Ruby's */
5565
static struct constat *
5566
constat_handle(HANDLE h)
5567
{
5568
    st_data_t data;
5569
    struct constat *p;
5570
    if (!conlist) {
5571
	conlist = st_init_numtable();
5572
    }
5573
    if (st_lookup(conlist, (st_data_t)h, &data)) {
5574
	p = (struct constat *)data;
5575
    }
5576
    else {
5577
	CONSOLE_SCREEN_BUFFER_INFO csbi;
5578
	p = ALLOC(struct constat);
5579
	p->vt100.state = constat_init;
5580
	p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
5581
	if (GetConsoleScreenBufferInfo(h, &csbi)) {
5582
	    p->vt100.attr = csbi.wAttributes;
5583
	}
5584
	st_insert(conlist, (st_data_t)h, (st_data_t)p);
5585
    }
5586
    return p;
5587
}
5588

  
5589
/* License: Ruby's */
5590
static void
5591
constat_reset(HANDLE h)
5592
{
5593
    st_data_t data;
5594
    struct constat *p;
5595
    if (!conlist) return;
5596
    if (!st_lookup(conlist, (st_data_t)h, &data)) return;
5597
    p = (struct constat *)data;
5598
    p->vt100.state = constat_init;
5599
}
5600

  
5601
/* License: Ruby's */
5602
static void
5603
constat_apply(HANDLE handle, const struct constat *s, WCHAR w)
5604
{
5605
    CONSOLE_SCREEN_BUFFER_INFO csbi;
5606
    const int *seq = s->vt100.seq;
5607
    int count = s->vt100.state;
5608
    int arg1 = 1;
5609
    int rev = 0;
5610
    COORD pos;
5611
    DWORD written, attr, bold;
5612
#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
5613
#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
5614

  
5615
    if (!GetConsoleScreenBufferInfo(handle, &csbi)) return;
5616
    if (count > 0 && seq[0] > 0) arg1 = seq[0];
5617
    switch (w) {
5618
      case L'm':
5619
	attr = csbi.wAttributes;
5620
	bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
5621
	if (count == 0) {
5622
	    attr = s->vt100.attr;
5623
	}
5624
	else {
5625
	    while (count-- > 0) {
5626
		switch (*seq++) {
5627
		  case 0:
5628
		    attr = s->vt100.attr;
5629
		    rev = 0;
5630
		    bold = 0;
5631
		    break;
5632
		  case 1:
5633
		    bold |= rev ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
5634
		    break;
5635
		  case 4:
5636
#ifndef COMMON_LVB_UNDERSCORE
5637
#define COMMON_LVB_UNDERSCORE 0x8000
5638
#endif
5639
		    attr |= COMMON_LVB_UNDERSCORE;
5640
		    break;
5641
		  case 7:
5642
		    rev = 1;
5643
		    break;
5644

  
5645
		  case 30:
5646
		    attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
5647
		    break;
5648
		  case 17:
5649
		  case 31:
5650
		    attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN) | FOREGROUND_RED;
5651
		    break;
5652
		  case 18:
5653
		  case 32:
5654
		    attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_RED) | FOREGROUND_GREEN;
5655
		    break;
5656
		  case 19:
5657
		  case 33:
5658
		    attr = attr & ~FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
5659
		    break;
5660
		  case 20:
5661
		  case 34:
5662
		    attr = attr & ~(FOREGROUND_GREEN | FOREGROUND_RED) | FOREGROUND_BLUE;
5663
		    break;
5664
		  case 21:
5665
		  case 35:
5666
		    attr = attr & ~FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
5667
		    break;
5668
		  case 22:
5669
		  case 36:
5670
		    attr = attr & ~FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
5671
		    break;
5672
		  case 23:
5673
		  case 37:
5674
		    attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
5675
		    break;
5676

  
5677
		  case 40:
5678
		    attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
5679
		  case 41:
5680
		    attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED;
5681
		    break;
5682
		  case 42:
5683
		    attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_RED) | BACKGROUND_GREEN;
5684
		    break;
5685
		  case 43:
5686
		    attr = attr & ~BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
5687
		    break;
5688
		  case 44:
5689
		    attr = attr & ~(BACKGROUND_GREEN | BACKGROUND_RED) | BACKGROUND_BLUE;
5690
		    break;
5691
		  case 45:
5692
		    attr = attr & ~BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
5693
		    break;
5694
		  case 46:
5695
		    attr = attr & ~BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN;
5696
		    break;
5697
		  case 47:
5698
		    attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
5699
		    break;
5700
		}
5701
	    }
5702
	}
5703
	if (rev) {
5704
	    attr = attr & ~(FOREGROUND_MASK | BACKGROUND_MASK) |
5705
		((attr & FOREGROUND_MASK) << 4) |
5706
		((attr & BACKGROUND_MASK) >> 4);
5707
	}
5708
	attr |= bold;
5709
	SetConsoleTextAttribute(handle, attr);
5710
	break;
5711
      case L'A':
5712
	csbi.dwCursorPosition.Y -= arg1;
5713
	if (csbi.dwCursorPosition.Y >= 0) {
5714
	    SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5715
	}
5716
	break;
5717
      case L'B':
5718
	csbi.dwCursorPosition.Y += arg1;
5719
	if (csbi.dwCursorPosition.Y < csbi.dwSize.Y) {
5720
	    SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5721
	}
5722
	break;
5723
      case L'C':
5724
	csbi.dwCursorPosition.X += arg1;
5725
	if (csbi.dwCursorPosition.X < csbi.dwSize.X) {
5726
	    SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5727
	}
5728
	break;
5729
      case L'D':
5730
	csbi.dwCursorPosition.X -= arg1;
5731
	if (csbi.dwCursorPosition.X >= 0) {
5732
	    SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5733
	}
5734
      case L'K':
5735
	switch (arg1) {
5736
	  case 0:	/* erase after cursor */
5737
	    FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X - csbi.dwCursorPosition.X, csbi.dwCursorPosition, &written);
5738
	    break;
5739
	  case 1:	/* erase before cursor */
5740
	    pos.X = 0;
5741
	    pos.Y = csbi.dwCursorPosition.Y;
5742
	    FillConsoleOutputCharacterW(handle, L' ', csbi.dwCursorPosition.X, pos, &written);
5743
	    break;
5744
	  case 2:	/* erase entire line */
5745
	    pos.X = 0;
5746
	    pos.Y = csbi.dwCursorPosition.Y;
5747
	    FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X, pos, &written);
5748
	    break;
5749
	}
5750
	break;
5751
    }
5752
}
5753

  
5754
static long
5755
constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
5756
{
5757
    const WCHAR *ptr = *ptrp;
5758
    long rest, len = *lenp;
5759
    while (len-- > 0) {
5760
	WCHAR wc = *ptr++;
5761
	if (wc == 0x1b) {
5762
	    rest = *lenp - len - 1;
5763
	    s->vt100.state = constat_esc;
5764
	}
5765
	else if (s->vt100.state == constat_esc && wc == L'[') {
5766
	    rest = *lenp - len - 1;
5767
	    if (rest > 0) --rest;
5768
	    s->vt100.state = constat_seq;
5769
	    s->vt100.seq[0] = 0;
5770
	}
5771
	else if (s->vt100.state >= constat_seq) {
5772
	    if (wc >= L'0' && wc <= L'9') {
5773
		if (s->vt100.state < (int)numberof(s->vt100.seq)) {
5774
		    int *seq = &s->vt100.seq[s->vt100.state];
5775
		    *seq = (*seq * 10) + (wc - L'0');
5776
		}
5777
	    }
5778
	    else {
5779
		if (++s->vt100.state < (int)numberof(s->vt100.seq)) {
5780
		    s->vt100.seq[s->vt100.state] = 0;
5781
		}
5782
		else {
5783
		    s->vt100.state = (int)numberof(s->vt100.seq);
5784
		}
5785
		if (wc != L';') {
5786
		    constat_apply(h, s, wc);
5787
		    s->vt100.state = constat_init;
5788
		}
5789
	    }
5790
	    rest = 0;
5791
	}
5792
	else {
5793
	    continue;
5794
	}
5795
	*ptrp = ptr;
5796
	*lenp = len;
5797
	return rest;
5798
    }
5799
    len = *lenp;
5800
    *ptrp = ptr;
5801
    *lenp = 0;
5802
    return len;
5803
}
5804

  
5805

  
5806
/* License: Ruby's */
5531 5807
int
5532 5808
rb_w32_close(int fd)
......
5541 5817
    _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
5542 5818
    socklist_delete(&sock, NULL);
5819
    constat_delete((HANDLE)sock);
5543 5820
    _close(fd);
5544 5821
    errno = save_errno;
......
5596 5873
    /* get rid of console reading bug */
5597 5874
    if (isconsole) {
5875
	constat_reset((HANDLE)_osfhnd(fd));
5598 5876
	if (start)
5599 5877
	    len = 1;
......
5848 6126
    DWORD dwMode, reslen;
5849 6127
    VALUE str = strarg;
6128
    rb_encoding *utf16 = rb_enc_find("UTF-16LE");
6129
    const WCHAR *ptr, *next;
6130
    struct constat *s;
6131
    long len;
5850 6132

  
5851 6133
    if (disable) return -1L;
......
5855 6137
	return -1L;
5856 6138

  
5857
    str = rb_str_encode(str, rb_enc_from_encoding(rb_enc_find("UTF-16LE")),
6139
    str = rb_str_encode(str, rb_enc_from_encoding(utf16),
5858 6140
			ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil);
5859
    if (!WriteConsoleW(handle, (LPWSTR)RSTRING_PTR(str), RSTRING_LEN(str)/2,
5860
		       &reslen, NULL)) {
5861
	if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
5862
	    disable = TRUE;
5863
	return -1L;
6141
    ptr = (const WCHAR *)RSTRING_PTR(str);
6142
    len = RSTRING_LEN(str) / sizeof(WCHAR);
6143
    s = constat_handle(handle);
6144
    while (len > 0) {
6145
	long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
6146
	if (curlen > 0) {
6147
	    if (!WriteConsoleW(handle, ptr, curlen, &reslen, NULL)) {
6148
		if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
6149
		    disable = TRUE;
6150
		return -1L;
6151
	    }
6152
	}
6153
	ptr = next;
5864 6154
    }
6155
    RB_GC_GUARD(str);
5865 6156
    return (long)reslen;
5866 6157
}