Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / libgo / go / net / textproto / writer.go
blob4e705f6c3ea1c89399a00dfaccb845e4d5837a9e
1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package textproto
7 import (
8 "bufio"
9 "fmt"
10 "io"
11 "os"
14 // A Writer implements convenience methods for writing
15 // requests or responses to a text protocol network connection.
16 type Writer struct {
17 W *bufio.Writer
18 dot *dotWriter
21 // NewWriter returns a new Writer writing to w.
22 func NewWriter(w *bufio.Writer) *Writer {
23 return &Writer{W: w}
26 var crnl = []byte{'\r', '\n'}
27 var dotcrnl = []byte{'.', '\r', '\n'}
29 // PrintfLine writes the formatted output followed by \r\n.
30 func (w *Writer) PrintfLine(format string, args ...interface{}) os.Error {
31 w.closeDot()
32 fmt.Fprintf(w.W, format, args...)
33 w.W.Write(crnl)
34 return w.W.Flush()
37 // DotWriter returns a writer that can be used to write a dot-encoding to w.
38 // It takes care of inserting leading dots when necessary,
39 // translating line-ending \n into \r\n, and adding the final .\r\n line
40 // when the DotWriter is closed. The caller should close the
41 // DotWriter before the next call to a method on w.
43 // See the documentation for Reader's DotReader method for details about dot-encoding.
44 func (w *Writer) DotWriter() io.WriteCloser {
45 w.closeDot()
46 w.dot = &dotWriter{w: w}
47 return w.dot
50 func (w *Writer) closeDot() {
51 if w.dot != nil {
52 w.dot.Close() // sets w.dot = nil
56 type dotWriter struct {
57 w *Writer
58 state int
61 const (
62 wstateBeginLine = iota // beginning of line; initial state; must be zero
63 wstateCR // wrote \r (possibly at end of line)
64 wstateData // writing data in middle of line
67 func (d *dotWriter) Write(b []byte) (n int, err os.Error) {
68 bw := d.w.W
69 for n < len(b) {
70 c := b[n]
71 switch d.state {
72 case wstateBeginLine:
73 d.state = wstateData
74 if c == '.' {
75 // escape leading dot
76 bw.WriteByte('.')
78 fallthrough
80 case wstateData:
81 if c == '\r' {
82 d.state = wstateCR
84 if c == '\n' {
85 bw.WriteByte('\r')
86 d.state = wstateBeginLine
89 case wstateCR:
90 d.state = wstateData
91 if c == '\n' {
92 d.state = wstateBeginLine
95 if err = bw.WriteByte(c); err != nil {
96 break
98 n++
100 return
103 func (d *dotWriter) Close() os.Error {
104 if d.w.dot == d {
105 d.w.dot = nil
107 bw := d.w.W
108 switch d.state {
109 default:
110 bw.WriteByte('\r')
111 fallthrough
112 case wstateCR:
113 bw.WriteByte('\n')
114 fallthrough
115 case wstateBeginLine:
116 bw.Write(dotcrnl)
118 return bw.Flush()