write.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package door
  2. import (
  3. "log"
  4. "regexp"
  5. "strconv"
  6. "strings"
  7. )
  8. var FindANSIColor *regexp.Regexp
  9. func init() {
  10. FindANSIColor = regexp.MustCompile("\x1b\\[([0-9;]*)m")
  11. }
  12. func find_ansicolor(text string) [][]int {
  13. var color_codes [][]int
  14. // word, _ := regexp.Compile("\x1b\\[([0-9;]+)m")
  15. colors := FindANSIColor.FindAllStringIndex(text, -1)
  16. // regexp seems to be ignoring the capture groups.
  17. // colors := word.FindAllSubmatchIndex([]byte(text), len(text))
  18. for _, pos := range colors {
  19. txt := text[pos[0]+2 : pos[1]-1]
  20. if txt == "" {
  21. txt = "0"
  22. }
  23. // log.Printf("Text: [%s]\n", txt)
  24. codes := strings.Split(txt, ";")
  25. // log.Printf("Codes: [%#v]\n", codes)
  26. code := make([]int, len(codes))
  27. for idx, c := range codes {
  28. var err error
  29. code[idx], err = strconv.Atoi(c)
  30. if err != nil {
  31. log.Printf("Atoi: %#v [%s]\n", err, c)
  32. }
  33. color_codes = append(color_codes, code)
  34. }
  35. }
  36. return color_codes
  37. }
  38. type ANSIColorParts struct {
  39. Bold bool
  40. Blink bool
  41. FG int
  42. BG int
  43. }
  44. func ParseColorArray(colorarray []int) ANSIColorParts {
  45. var acp ANSIColorParts
  46. acp.FG = -1
  47. acp.BG = -1
  48. for _, c := range colorarray {
  49. switch c {
  50. case 0:
  51. acp.FG = 7
  52. acp.BG = 0
  53. case 1:
  54. acp.Bold = true
  55. case 5:
  56. acp.Blink = true
  57. case 30, 31, 32, 33, 34, 35, 36, 37:
  58. acp.FG = c - 30
  59. case 40, 41, 42, 43, 44, 45, 46, 47:
  60. acp.BG = c - 40
  61. }
  62. }
  63. return acp
  64. }
  65. func (d *Door) ParseLastColor(output string) {
  66. // use the last color information + whatever is in the string to
  67. // track the last color set
  68. updated := ParseColorArray(d.LastColor)
  69. colors := find_ansicolor(output)
  70. for _, codes := range colors {
  71. if codes[0] == 0 {
  72. updated = ParseColorArray(codes)
  73. } else {
  74. newCode := ParseColorArray(codes)
  75. if newCode.Bold {
  76. updated.Bold = true
  77. }
  78. if newCode.Blink {
  79. updated.Blink = true
  80. }
  81. if (newCode.FG != -1) && (newCode.FG != updated.FG) {
  82. updated.FG = newCode.FG
  83. }
  84. if (newCode.BG != -1) && (newCode.BG != updated.BG) {
  85. updated.BG = newCode.BG
  86. }
  87. }
  88. }
  89. d.LastColor = make([]int, 1)
  90. d.LastColor[0] = 0
  91. if updated.Blink {
  92. d.LastColor = append(d.LastColor, 5)
  93. }
  94. if updated.Bold {
  95. d.LastColor = append(d.LastColor, 1)
  96. }
  97. if updated.FG != -1 {
  98. d.LastColor = append(d.LastColor, updated.FG+30)
  99. }
  100. if updated.BG != -1 {
  101. d.LastColor = append(d.LastColor, updated.BG+40)
  102. }
  103. }
  104. /*
  105. reading from a closed channel is easy to detect.
  106. res, ok := <-channel
  107. ok == false
  108. writing to a closed channel is a panic.
  109. */
  110. var writerChannel chan string
  111. // Write string to client.
  112. func (d *Door) Write(output string) {
  113. if d.Disconnected {
  114. return
  115. }
  116. defer func() {
  117. if r := recover(); r != nil {
  118. log.Println("Write error/HANGUP.")
  119. d.Disconnected = true
  120. }
  121. }()
  122. if strings.HasSuffix(output, RestorePos) {
  123. output += Color(d.LastColor...)
  124. } else {
  125. d.ParseLastColor(output)
  126. }
  127. /*
  128. temp := strings.Replace(output, "\x1b", "^[", -1)
  129. log.Printf("Parse: [%s]\n", temp)
  130. */
  131. writerChannel <- output
  132. /*
  133. buffer := []byte(output)
  134. n, err := syscall.Write(d.WRITEFD, buffer)
  135. if err != nil {
  136. fmt.Println("Write error/HANGUP?", n)
  137. d.Disconnected = true
  138. }
  139. // No, this isn't it. The # of bytes in buffer == bytes written.
  140. if n != len(buffer) {
  141. fmt.Printf("Write fail: %d != %d\n", len(buffer), n)
  142. }
  143. */
  144. }