write_linux.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. package door
  2. import (
  3. "bytes"
  4. "syscall"
  5. )
  6. // OS Specific Write
  7. // This assumes that d.writerMutex is locked.
  8. type OSWriter struct {
  9. Handle int
  10. BaseWriter
  11. }
  12. func (ow *OSWriter) Init(d *Door) {
  13. ow.Closed = false
  14. ow.Handle = d.Config.Comm_handle
  15. ow.TranslateNL = true // Yes, translate NL => CR+NL
  16. ow.nlBuffer = &bytes.Buffer{}
  17. // ow.restoreBuff = &bytes.Buffer{}
  18. ow.ansiCode = make([]byte, 0, 32)
  19. }
  20. func (ow *OSWriter) CP437toUnicode(output []byte) []byte {
  21. if ow.uniBuffer == nil {
  22. ow.uniBuffer = &bytes.Buffer{}
  23. }
  24. for _, ch := range output {
  25. // Perform translation here
  26. ow.uniBuffer.WriteByte(ch)
  27. }
  28. return ow.uniBuffer.Bytes()
  29. }
  30. func (ow *OSWriter) NewLines(output []byte) []byte {
  31. var pos, nextpos int
  32. ow.nlBuffer.Reset()
  33. for pos != -1 {
  34. nextpos = bytes.Index(output[pos:], []byte{'\n'})
  35. if nextpos != -1 {
  36. nextpos += pos
  37. // Something to do
  38. ow.nlBuffer.Write(output[pos:nextpos])
  39. nextpos++
  40. pos = nextpos
  41. ow.nlBuffer.Write([]byte("\r\n"))
  42. } else {
  43. ow.nlBuffer.Write(output[pos:])
  44. pos = nextpos // -1
  45. }
  46. }
  47. // log.Printf(">> %q\n", ow.nlBuffer.Bytes())
  48. return ow.nlBuffer.Bytes()
  49. }
  50. /*
  51. // Read byte slice, add color restore (after restorepos).
  52. func (ow *OSWriter) HandleRestoreColor(output []byte) []byte {
  53. // Parse out ANSI codes:
  54. // Look for m (color), s (savepos), u (restorepos)
  55. // Possibly H (goto)
  56. ow.restoreBuff.Reset()
  57. var changed bool
  58. var pos, nextpos int
  59. var outputLen int = len(output)
  60. // Handle the case where the CSI code continues...
  61. if ow.ansiCSI {
  62. // Continue processing CSI code
  63. var c byte
  64. for pos != outputLen {
  65. c = output[pos]
  66. pos++
  67. ow.ansiCode = append(ow.ansiCode, c)
  68. if (c >= 0x40) && (c <= 0x7f) {
  69. // Found it
  70. ow.ansiCSI = false
  71. break
  72. }
  73. }
  74. ow.restoreBuff.Write(output[0:pos])
  75. pos++
  76. if !ow.ansiCSI {
  77. log.Printf("CSI: %c [%q]\n", c, ow.ansiCode)
  78. // Process this code (if of interest)
  79. // Reset the buffer
  80. ow.ansiCode = ow.ansiCode[0:0]
  81. }
  82. }
  83. // To verify that we're keeping the buffer in the proper state
  84. changed = true
  85. log.Printf("raw: [%q]\n", output)
  86. for pos != -1 {
  87. nextpos = bytes.Index(output[pos:], []byte{'\x1b'})
  88. if nextpos != -1 {
  89. nextpos += pos
  90. // Output everything up to the \x1b
  91. ow.restoreBuff.Write(output[pos:nextpos])
  92. // Found ESC
  93. if output[nextpos+1] == '[' {
  94. // Found CSI start
  95. // https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences
  96. ow.ansiCSI = true
  97. // While not the end, and not end of CSI, append to ansiCode
  98. var csiPos int = nextpos + 2
  99. var c byte
  100. for csiPos != outputLen {
  101. c = output[csiPos]
  102. csiPos++
  103. ow.ansiCode = append(ow.ansiCode, c)
  104. if (c >= 0x40) && (c <= 0x7f) {
  105. // FOUND IT!
  106. ow.ansiCSI = false
  107. break
  108. }
  109. }
  110. // Write out the CSI code (or what we have of it)
  111. ow.restoreBuff.Write(output[nextpos:csiPos])
  112. nextpos = csiPos
  113. if !ow.ansiCSI {
  114. log.Printf("CSI: %c [%q]\n", c, ow.ansiCode)
  115. // Process this code (if of interest)
  116. // Reset the buffer
  117. ow.ansiCode = ow.ansiCode[0:0]
  118. }
  119. } else {
  120. ow.restoreBuff.WriteByte('\x1b')
  121. nextpos++
  122. }
  123. pos = nextpos
  124. } else {
  125. ow.restoreBuff.Write(output[pos:])
  126. pos = nextpos // -1 (end)
  127. }
  128. }
  129. // log.Printf("<< [%q]\n>> [%q]\n", output, ow.restoreBuff.Bytes())
  130. if changed {
  131. return ow.restoreBuff.Bytes()
  132. } else {
  133. return output
  134. }
  135. }
  136. */
  137. // The low-lever writer function
  138. func (ow *OSWriter) OSWrite(buffer []byte) (int, error) {
  139. var buff []byte = buffer
  140. // Filters (!)
  141. if ow.TranslateNL {
  142. buff = ow.NewLines(buff)
  143. }
  144. n, err := syscall.Write(ow.Handle, buff)
  145. if (err != nil) || (n != len(buff)) {
  146. if !ow.Closed {
  147. ow.Closed = true
  148. // Don't need to close reader, it will close itself.
  149. // It knows when the caller is gone before the writer ever will!
  150. }
  151. }
  152. return n, err
  153. }
  154. func (ow *OSWriter) Write(buffer []byte) (int, error) {
  155. if ow.Closed {
  156. return 0, ErrDisconnected
  157. }
  158. return ow.OSWrite(buffer)
  159. }
  160. func (ow *OSWriter) Stop() {
  161. ow.Closed = true
  162. }
  163. // Safe way to check if OSWriter is closed
  164. func (ow *OSWriter) IsClosed() bool {
  165. return ow.Closed
  166. }
  167. // deprecated
  168. /*
  169. func (d *Door) OSWrite(buffer []byte) {
  170. if d.WriterClosed {
  171. return
  172. }
  173. if DEBUG_DOOR {
  174. if d.writerMutex.TryLock() {
  175. log.Panicln("OSWrite: writerMutex was NOT locked.")
  176. }
  177. }
  178. n, err := syscall.Write(d.Config.Comm_handle, buffer)
  179. if (err != nil) || (n != len(buffer)) {
  180. if !d.WriterClosed {
  181. d.WriterClosed = true
  182. }
  183. }
  184. }
  185. */
  186. // Deprecated
  187. // This is the writer go routine.
  188. /*
  189. // The parts of interest that I'm holding off on implementing for right now.
  190. if strings.HasSuffix(output, RestorePos) {
  191. output += Color(d.LastColor)
  192. } else {
  193. d.UpdateLastColor(output, &d.LastColor)
  194. }
  195. buffer := []byte(output)
  196. // n, err := low_write(handle, buffer)
  197. n, err := syscall.Write(handle, buffer)
  198. if (err != nil) || (n != len(buffer)) {
  199. log.Println("closeChannel")
  200. Closed = true
  201. d.writerMutex.Lock()
  202. if !d.WriterClosed {
  203. d.WriterClosed = true
  204. // close(d.writerChannel)
  205. }
  206. d.writerMutex.Unlock()
  207. }
  208. */