package door import ( "bytes" "syscall" ) // OS Specific Write // This assumes that d.writerMutex is locked. type OSWriter struct { Handle int BaseWriter } func (ow *OSWriter) Init(d *Door) { ow.Closed = false ow.Handle = d.Config.Comm_handle ow.TranslateNL = true // Yes, translate NL => CR+NL ow.nlBuffer = &bytes.Buffer{} // ow.restoreBuff = &bytes.Buffer{} ow.ansiCode = make([]byte, 0, 32) } func (ow *OSWriter) CP437toUnicode(output []byte) []byte { if ow.uniBuffer == nil { ow.uniBuffer = &bytes.Buffer{} } for _, ch := range output { // Perform translation here ow.uniBuffer.WriteByte(ch) } return ow.uniBuffer.Bytes() } func (ow *OSWriter) NewLines(output []byte) []byte { var pos, nextpos int ow.nlBuffer.Reset() for pos != -1 { nextpos = bytes.Index(output[pos:], []byte{'\n'}) if nextpos != -1 { nextpos += pos // Something to do ow.nlBuffer.Write(output[pos:nextpos]) nextpos++ pos = nextpos ow.nlBuffer.Write([]byte("\r\n")) } else { ow.nlBuffer.Write(output[pos:]) pos = nextpos // -1 } } // log.Printf(">> %q\n", ow.nlBuffer.Bytes()) return ow.nlBuffer.Bytes() } /* // Read byte slice, add color restore (after restorepos). func (ow *OSWriter) HandleRestoreColor(output []byte) []byte { // Parse out ANSI codes: // Look for m (color), s (savepos), u (restorepos) // Possibly H (goto) ow.restoreBuff.Reset() var changed bool var pos, nextpos int var outputLen int = len(output) // Handle the case where the CSI code continues... if ow.ansiCSI { // Continue processing CSI code var c byte for pos != outputLen { c = output[pos] pos++ ow.ansiCode = append(ow.ansiCode, c) if (c >= 0x40) && (c <= 0x7f) { // Found it ow.ansiCSI = false break } } ow.restoreBuff.Write(output[0:pos]) pos++ if !ow.ansiCSI { log.Printf("CSI: %c [%q]\n", c, ow.ansiCode) // Process this code (if of interest) // Reset the buffer ow.ansiCode = ow.ansiCode[0:0] } } // To verify that we're keeping the buffer in the proper state changed = true log.Printf("raw: [%q]\n", output) for pos != -1 { nextpos = bytes.Index(output[pos:], []byte{'\x1b'}) if nextpos != -1 { nextpos += pos // Output everything up to the \x1b ow.restoreBuff.Write(output[pos:nextpos]) // Found ESC if output[nextpos+1] == '[' { // Found CSI start // https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences ow.ansiCSI = true // While not the end, and not end of CSI, append to ansiCode var csiPos int = nextpos + 2 var c byte for csiPos != outputLen { c = output[csiPos] csiPos++ ow.ansiCode = append(ow.ansiCode, c) if (c >= 0x40) && (c <= 0x7f) { // FOUND IT! ow.ansiCSI = false break } } // Write out the CSI code (or what we have of it) ow.restoreBuff.Write(output[nextpos:csiPos]) nextpos = csiPos if !ow.ansiCSI { log.Printf("CSI: %c [%q]\n", c, ow.ansiCode) // Process this code (if of interest) // Reset the buffer ow.ansiCode = ow.ansiCode[0:0] } } else { ow.restoreBuff.WriteByte('\x1b') nextpos++ } pos = nextpos } else { ow.restoreBuff.Write(output[pos:]) pos = nextpos // -1 (end) } } // log.Printf("<< [%q]\n>> [%q]\n", output, ow.restoreBuff.Bytes()) if changed { return ow.restoreBuff.Bytes() } else { return output } } */ // The low-lever writer function func (ow *OSWriter) OSWrite(buffer []byte) (int, error) { var buff []byte = buffer // Filters (!) if ow.TranslateNL { buff = ow.NewLines(buff) } n, err := syscall.Write(ow.Handle, buff) if (err != nil) || (n != len(buff)) { if !ow.Closed { ow.Closed = true // Don't need to close reader, it will close itself. // It knows when the caller is gone before the writer ever will! } } return n, err } func (ow *OSWriter) Write(buffer []byte) (int, error) { if ow.Closed { return 0, ErrDisconnected } return ow.OSWrite(buffer) } func (ow *OSWriter) Stop() { ow.Closed = true } // Safe way to check if OSWriter is closed func (ow *OSWriter) IsClosed() bool { return ow.Closed } // deprecated /* func (d *Door) OSWrite(buffer []byte) { if d.WriterClosed { return } if DEBUG_DOOR { if d.writerMutex.TryLock() { log.Panicln("OSWrite: writerMutex was NOT locked.") } } n, err := syscall.Write(d.Config.Comm_handle, buffer) if (err != nil) || (n != len(buffer)) { if !d.WriterClosed { d.WriterClosed = true } } } */ // Deprecated // This is the writer go routine. /* // The parts of interest that I'm holding off on implementing for right now. if strings.HasSuffix(output, RestorePos) { output += Color(d.LastColor) } else { d.UpdateLastColor(output, &d.LastColor) } buffer := []byte(output) // n, err := low_write(handle, buffer) n, err := syscall.Write(handle, buffer) if (err != nil) || (n != len(buffer)) { log.Println("closeChannel") Closed = true d.writerMutex.Lock() if !d.WriterClosed { d.WriterClosed = true // close(d.writerChannel) } d.writerMutex.Unlock() } */