write_linux.go 3.6 KB

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