| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 | package doorimport (	"log"	"regexp"	"strconv"	"strings")var FindANSIColor *regexp.Regexpfunc init() {	FindANSIColor = regexp.MustCompile("\x1b\\[([0-9;]*)m")}func find_ansicolor(text string) [][]int {	var color_codes [][]int	// word, _ := regexp.Compile("\x1b\\[([0-9;]+)m")	colors := FindANSIColor.FindAllStringIndex(text, -1)	// regexp seems to be ignoring the capture groups.	// colors := word.FindAllSubmatchIndex([]byte(text), len(text))	for _, pos := range colors {		txt := text[pos[0]+2 : pos[1]-1]		if txt == "" {			txt = "0"		}		// log.Printf("Text: [%s]\n", txt)		codes := strings.Split(txt, ";")		// log.Printf("Codes: [%#v]\n", codes)		code := make([]int, len(codes))		for idx, c := range codes {			var err error			code[idx], err = strconv.Atoi(c)			if err != nil {				log.Printf("Atoi: %#v [%s]\n", err, c)			}			color_codes = append(color_codes, code)		}	}	return color_codes}type ANSIColorParts struct {	Bold  bool	Blink bool	FG    int	BG    int}func ParseColorArray(colorarray []int) ANSIColorParts {	var acp ANSIColorParts	acp.FG = -1	acp.BG = -1	for _, c := range colorarray {		switch c {		case 0:			acp.FG = 7			acp.BG = 0		case 1:			acp.Bold = true		case 5:			acp.Blink = true		case 30, 31, 32, 33, 34, 35, 36, 37:			acp.FG = c - 30		case 40, 41, 42, 43, 44, 45, 46, 47:			acp.BG = c - 40		}	}	return acp}func (d *Door) ParseLastColor(output string) {	// use the last color information + whatever is in the string to	// track the last color set	updated := ParseColorArray(d.LastColor)	colors := find_ansicolor(output)	for _, codes := range colors {		if codes[0] == 0 {			updated = ParseColorArray(codes)		} else {			newCode := ParseColorArray(codes)			if newCode.Bold {				updated.Bold = true			}			if newCode.Blink {				updated.Blink = true			}			if (newCode.FG != -1) && (newCode.FG != updated.FG) {				updated.FG = newCode.FG			}			if (newCode.BG != -1) && (newCode.BG != updated.BG) {				updated.BG = newCode.BG			}		}	}	d.LastColor = make([]int, 1)	d.LastColor[0] = 0	if updated.Blink {		d.LastColor = append(d.LastColor, 5)	}	if updated.Bold {		d.LastColor = append(d.LastColor, 1)	}	if updated.FG != -1 {		d.LastColor = append(d.LastColor, updated.FG+30)	}	if updated.BG != -1 {		d.LastColor = append(d.LastColor, updated.BG+40)	}}/*reading from a closed channel is easy to detect.res, ok := <-channelok == falsewriting to a closed channel is a panic.*/var writerChannel chan string// Write string to client.func (d *Door) Write(output string) {	if d.Disconnected {		return	}	defer func() {		if r := recover(); r != nil {			log.Println("Write error/HANGUP.")			d.Disconnected = true		}	}()	if strings.HasSuffix(output, RestorePos) {		output += Color(d.LastColor...)	} else {		d.ParseLastColor(output)	}	/*		temp := strings.Replace(output, "\x1b", "^[", -1)		log.Printf("Parse: [%s]\n", temp)	*/	writerChannel <- output	/*		buffer := []byte(output)		n, err := syscall.Write(d.WRITEFD, buffer)		if err != nil {			fmt.Println("Write error/HANGUP?", n)			d.Disconnected = true		}		// No, this isn't it.  The # of bytes in buffer == bytes written.		if n != len(buffer) {			fmt.Printf("Write fail: %d != %d\n", len(buffer), n)		}	*/}
 |