@@ -33,7 +33,7 @@ type bufferedWriteCloser struct {
3333 io.Closer
3434}
3535
36- func newBufferedWriteClose (w io.WriteCloser ) * bufferedWriteCloser {
36+ func newBufferedWriteCloser (w io.WriteCloser ) * bufferedWriteCloser {
3737 writer := bufio .NewWriterSize (w , outputBufSize )
3838 return & bufferedWriteCloser {writer , w }
3939}
@@ -76,6 +76,7 @@ func (p *interp) getOutputStream(redirect Token, dest Expr) (io.Writer, error) {
7676 if p .noFileWrites {
7777 return nil , newError ("can't write to file due to NoFileWrites" )
7878 }
79+ p .flushOutputAndError () // ensure synchronization
7980 flags := os .O_CREATE | os .O_WRONLY
8081 if redirect == GREATER {
8182 flags |= os .O_TRUNC
@@ -86,7 +87,7 @@ func (p *interp) getOutputStream(redirect Token, dest Expr) (io.Writer, error) {
8687 if err != nil {
8788 return nil , newError ("output redirection error: %s" , err )
8889 }
89- buffered := newBufferedWriteClose (w )
90+ buffered := newBufferedWriteCloser (w )
9091 p .outputStreams [name ] = buffered
9192 return buffered , nil
9293
@@ -102,13 +103,14 @@ func (p *interp) getOutputStream(redirect Token, dest Expr) (io.Writer, error) {
102103 }
103104 cmd .Stdout = p .output
104105 cmd .Stderr = p .errorOutput
106+ p .flushOutputAndError () // ensure synchronization
105107 err = cmd .Start ()
106108 if err != nil {
107- fmt . Fprintln ( p . errorOutput , err )
109+ p . printErrorf ( "%s \n " , err )
108110 return ioutil .Discard , nil
109111 }
110112 p .commands [name ] = cmd
111- buffered := newBufferedWriteClose (w )
113+ buffered := newBufferedWriteCloser (w )
112114 p .outputStreams [name ] = buffered
113115 return buffered , nil
114116
@@ -166,9 +168,10 @@ func (p *interp) getInputScannerPipe(name string) (*bufio.Scanner, error) {
166168 if err != nil {
167169 return nil , newError ("error connecting to stdout pipe: %v" , err )
168170 }
171+ p .flushOutputAndError () // ensure synchronization
169172 err = cmd .Start ()
170173 if err != nil {
171- fmt . Fprintln ( p . errorOutput , err )
174+ p . printErrorf ( "%s \n " , err )
172175 return bufio .NewScanner (strings .NewReader ("" )), nil
173176 }
174177 scanner := p .newScanner (r )
@@ -468,7 +471,7 @@ func (p *interp) flushAll() bool {
468471func (p * interp ) flushStream (name string ) bool {
469472 writer := p .outputStreams [name ]
470473 if writer == nil {
471- fmt . Fprintf ( p . errorOutput , "error flushing %q: not an output file or pipe\n " , name )
474+ p . printErrorf ( "error flushing %q: not an output file or pipe\n " , name )
472475 return false
473476 }
474477 return p .flushWriter (name , writer )
@@ -481,11 +484,35 @@ type flusher interface {
481484// Flush given output writer, and report whether it was flushed successfully
482485// (logging an error if not).
483486func (p * interp ) flushWriter (name string , writer io.Writer ) bool {
484- flusher := writer .(flusher )
487+ flusher , ok := writer .(flusher )
488+ if ! ok {
489+ return true // not a flusher, don't error
490+ }
485491 err := flusher .Flush ()
486492 if err != nil {
487- fmt . Fprintf ( p . errorOutput , "error flushing %q: %v\n " , name , err )
493+ p . printErrorf ( "error flushing %q: %v\n " , name , err )
488494 return false
489495 }
490496 return true
491497}
498+
499+ // Flush output and error streams.
500+ func (p * interp ) flushOutputAndError () {
501+ if flusher , ok := p .output .(flusher ); ok {
502+ _ = flusher .Flush ()
503+ }
504+ if flusher , ok := p .errorOutput .(flusher ); ok {
505+ _ = flusher .Flush ()
506+ }
507+ }
508+
509+ // Print a message to the error output stream, flushing as necessary.
510+ func (p * interp ) printErrorf (format string , args ... interface {}) {
511+ if flusher , ok := p .output .(flusher ); ok {
512+ _ = flusher .Flush () // ensure synchronization
513+ }
514+ fmt .Fprintf (p .errorOutput , format , args ... )
515+ if flusher , ok := p .errorOutput .(flusher ); ok {
516+ _ = flusher .Flush ()
517+ }
518+ }
0 commit comments