mirror of
https://github.com/go-gitea/gitea.git
synced 2025-06-22 14:08:01 +02:00
Integrate public as bindata optionally (#293)
* Dropped unused codekit config * Integrated dynamic and static bindata for public * Ignore public bindata * Add a general generate make task * Integrated flexible public assets into web command * Updated vendoring, added all missiong govendor deps * Made the linter happy with the bindata and dynamic code * Moved public bindata definition to modules directory * Ignoring the new bindata path now * Updated to the new public modules import path * Updated public bindata command and drop the new prefix
This commit is contained in:

committed by
Lunny Xiao

parent
4680c349dd
commit
b6a95a8cb3
20
vendor/gopkg.in/alexcesaro/quotedprintable.v3/LICENSE
generated
vendored
Normal file
20
vendor/gopkg.in/alexcesaro/quotedprintable.v3/LICENSE
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Alexandre Cesaro
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
vendor/gopkg.in/alexcesaro/quotedprintable.v3/README.md
generated
vendored
Normal file
16
vendor/gopkg.in/alexcesaro/quotedprintable.v3/README.md
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# quotedprintable
|
||||
|
||||
## Introduction
|
||||
|
||||
Package quotedprintable implements quoted-printable and message header encoding
|
||||
as specified by RFC 2045 and RFC 2047.
|
||||
|
||||
It is a copy of the Go 1.5 package `mime/quotedprintable`. It also includes
|
||||
the new functions of package `mime` concerning RFC 2047.
|
||||
|
||||
This code has minor changes with the standard library code in order to work
|
||||
with Go 1.0 and newer.
|
||||
|
||||
## Documentation
|
||||
|
||||
https://godoc.org/gopkg.in/alexcesaro/quotedprintable.v3
|
279
vendor/gopkg.in/alexcesaro/quotedprintable.v3/encodedword.go
generated
vendored
Normal file
279
vendor/gopkg.in/alexcesaro/quotedprintable.v3/encodedword.go
generated
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
package quotedprintable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// A WordEncoder is a RFC 2047 encoded-word encoder.
|
||||
type WordEncoder byte
|
||||
|
||||
const (
|
||||
// BEncoding represents Base64 encoding scheme as defined by RFC 2045.
|
||||
BEncoding = WordEncoder('b')
|
||||
// QEncoding represents the Q-encoding scheme as defined by RFC 2047.
|
||||
QEncoding = WordEncoder('q')
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidWord = errors.New("mime: invalid RFC 2047 encoded-word")
|
||||
)
|
||||
|
||||
// Encode returns the encoded-word form of s. If s is ASCII without special
|
||||
// characters, it is returned unchanged. The provided charset is the IANA
|
||||
// charset name of s. It is case insensitive.
|
||||
func (e WordEncoder) Encode(charset, s string) string {
|
||||
if !needsEncoding(s) {
|
||||
return s
|
||||
}
|
||||
return e.encodeWord(charset, s)
|
||||
}
|
||||
|
||||
func needsEncoding(s string) bool {
|
||||
for _, b := range s {
|
||||
if (b < ' ' || b > '~') && b != '\t' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// encodeWord encodes a string into an encoded-word.
|
||||
func (e WordEncoder) encodeWord(charset, s string) string {
|
||||
buf := getBuffer()
|
||||
defer putBuffer(buf)
|
||||
|
||||
buf.WriteString("=?")
|
||||
buf.WriteString(charset)
|
||||
buf.WriteByte('?')
|
||||
buf.WriteByte(byte(e))
|
||||
buf.WriteByte('?')
|
||||
|
||||
if e == BEncoding {
|
||||
w := base64.NewEncoder(base64.StdEncoding, buf)
|
||||
io.WriteString(w, s)
|
||||
w.Close()
|
||||
} else {
|
||||
enc := make([]byte, 3)
|
||||
for i := 0; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch {
|
||||
case b == ' ':
|
||||
buf.WriteByte('_')
|
||||
case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_':
|
||||
buf.WriteByte(b)
|
||||
default:
|
||||
enc[0] = '='
|
||||
enc[1] = upperhex[b>>4]
|
||||
enc[2] = upperhex[b&0x0f]
|
||||
buf.Write(enc)
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.WriteString("?=")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
const upperhex = "0123456789ABCDEF"
|
||||
|
||||
// A WordDecoder decodes MIME headers containing RFC 2047 encoded-words.
|
||||
type WordDecoder struct {
|
||||
// CharsetReader, if non-nil, defines a function to generate
|
||||
// charset-conversion readers, converting from the provided
|
||||
// charset into UTF-8.
|
||||
// Charsets are always lower-case. utf-8, iso-8859-1 and us-ascii charsets
|
||||
// are handled by default.
|
||||
// One of the the CharsetReader's result values must be non-nil.
|
||||
CharsetReader func(charset string, input io.Reader) (io.Reader, error)
|
||||
}
|
||||
|
||||
// Decode decodes an encoded-word. If word is not a valid RFC 2047 encoded-word,
|
||||
// word is returned unchanged.
|
||||
func (d *WordDecoder) Decode(word string) (string, error) {
|
||||
fields := strings.Split(word, "?") // TODO: remove allocation?
|
||||
if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" || len(fields[2]) != 1 {
|
||||
return "", errInvalidWord
|
||||
}
|
||||
|
||||
content, err := decode(fields[2][0], fields[3])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf := getBuffer()
|
||||
defer putBuffer(buf)
|
||||
|
||||
if err := d.convert(buf, fields[1], content); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// DecodeHeader decodes all encoded-words of the given string. It returns an
|
||||
// error if and only if CharsetReader of d returns an error.
|
||||
func (d *WordDecoder) DecodeHeader(header string) (string, error) {
|
||||
// If there is no encoded-word, returns before creating a buffer.
|
||||
i := strings.Index(header, "=?")
|
||||
if i == -1 {
|
||||
return header, nil
|
||||
}
|
||||
|
||||
buf := getBuffer()
|
||||
defer putBuffer(buf)
|
||||
|
||||
buf.WriteString(header[:i])
|
||||
header = header[i:]
|
||||
|
||||
betweenWords := false
|
||||
for {
|
||||
start := strings.Index(header, "=?")
|
||||
if start == -1 {
|
||||
break
|
||||
}
|
||||
cur := start + len("=?")
|
||||
|
||||
i := strings.Index(header[cur:], "?")
|
||||
if i == -1 {
|
||||
break
|
||||
}
|
||||
charset := header[cur : cur+i]
|
||||
cur += i + len("?")
|
||||
|
||||
if len(header) < cur+len("Q??=") {
|
||||
break
|
||||
}
|
||||
encoding := header[cur]
|
||||
cur++
|
||||
|
||||
if header[cur] != '?' {
|
||||
break
|
||||
}
|
||||
cur++
|
||||
|
||||
j := strings.Index(header[cur:], "?=")
|
||||
if j == -1 {
|
||||
break
|
||||
}
|
||||
text := header[cur : cur+j]
|
||||
end := cur + j + len("?=")
|
||||
|
||||
content, err := decode(encoding, text)
|
||||
if err != nil {
|
||||
betweenWords = false
|
||||
buf.WriteString(header[:start+2])
|
||||
header = header[start+2:]
|
||||
continue
|
||||
}
|
||||
|
||||
// Write characters before the encoded-word. White-space and newline
|
||||
// characters separating two encoded-words must be deleted.
|
||||
if start > 0 && (!betweenWords || hasNonWhitespace(header[:start])) {
|
||||
buf.WriteString(header[:start])
|
||||
}
|
||||
|
||||
if err := d.convert(buf, charset, content); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
header = header[end:]
|
||||
betweenWords = true
|
||||
}
|
||||
|
||||
if len(header) > 0 {
|
||||
buf.WriteString(header)
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func decode(encoding byte, text string) ([]byte, error) {
|
||||
switch encoding {
|
||||
case 'B', 'b':
|
||||
return base64.StdEncoding.DecodeString(text)
|
||||
case 'Q', 'q':
|
||||
return qDecode(text)
|
||||
}
|
||||
return nil, errInvalidWord
|
||||
}
|
||||
|
||||
func (d *WordDecoder) convert(buf *bytes.Buffer, charset string, content []byte) error {
|
||||
switch {
|
||||
case strings.EqualFold("utf-8", charset):
|
||||
buf.Write(content)
|
||||
case strings.EqualFold("iso-8859-1", charset):
|
||||
for _, c := range content {
|
||||
buf.WriteRune(rune(c))
|
||||
}
|
||||
case strings.EqualFold("us-ascii", charset):
|
||||
for _, c := range content {
|
||||
if c >= utf8.RuneSelf {
|
||||
buf.WriteRune(unicode.ReplacementChar)
|
||||
} else {
|
||||
buf.WriteByte(c)
|
||||
}
|
||||
}
|
||||
default:
|
||||
if d.CharsetReader == nil {
|
||||
return fmt.Errorf("mime: unhandled charset %q", charset)
|
||||
}
|
||||
r, err := d.CharsetReader(strings.ToLower(charset), bytes.NewReader(content))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = buf.ReadFrom(r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// hasNonWhitespace reports whether s (assumed to be ASCII) contains at least
|
||||
// one byte of non-whitespace.
|
||||
func hasNonWhitespace(s string) bool {
|
||||
for _, b := range s {
|
||||
switch b {
|
||||
// Encoded-words can only be separated by linear white spaces which does
|
||||
// not include vertical tabs (\v).
|
||||
case ' ', '\t', '\n', '\r':
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// qDecode decodes a Q encoded string.
|
||||
func qDecode(s string) ([]byte, error) {
|
||||
dec := make([]byte, len(s))
|
||||
n := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch c := s[i]; {
|
||||
case c == '_':
|
||||
dec[n] = ' '
|
||||
case c == '=':
|
||||
if i+2 >= len(s) {
|
||||
return nil, errInvalidWord
|
||||
}
|
||||
b, err := readHexByte(s[i+1], s[i+2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dec[n] = b
|
||||
i += 2
|
||||
case (c <= '~' && c >= ' ') || c == '\n' || c == '\r' || c == '\t':
|
||||
dec[n] = c
|
||||
default:
|
||||
return nil, errInvalidWord
|
||||
}
|
||||
n++
|
||||
}
|
||||
|
||||
return dec[:n], nil
|
||||
}
|
26
vendor/gopkg.in/alexcesaro/quotedprintable.v3/pool.go
generated
vendored
Normal file
26
vendor/gopkg.in/alexcesaro/quotedprintable.v3/pool.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// +build go1.3
|
||||
|
||||
package quotedprintable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
func getBuffer() *bytes.Buffer {
|
||||
return bufPool.Get().(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func putBuffer(buf *bytes.Buffer) {
|
||||
if buf.Len() > 1024 {
|
||||
return
|
||||
}
|
||||
buf.Reset()
|
||||
bufPool.Put(buf)
|
||||
}
|
24
vendor/gopkg.in/alexcesaro/quotedprintable.v3/pool_go12.go
generated
vendored
Normal file
24
vendor/gopkg.in/alexcesaro/quotedprintable.v3/pool_go12.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// +build !go1.3
|
||||
|
||||
package quotedprintable
|
||||
|
||||
import "bytes"
|
||||
|
||||
var ch = make(chan *bytes.Buffer, 32)
|
||||
|
||||
func getBuffer() *bytes.Buffer {
|
||||
select {
|
||||
case buf := <-ch:
|
||||
return buf
|
||||
default:
|
||||
}
|
||||
return new(bytes.Buffer)
|
||||
}
|
||||
|
||||
func putBuffer(buf *bytes.Buffer) {
|
||||
buf.Reset()
|
||||
select {
|
||||
case ch <- buf:
|
||||
default:
|
||||
}
|
||||
}
|
121
vendor/gopkg.in/alexcesaro/quotedprintable.v3/reader.go
generated
vendored
Normal file
121
vendor/gopkg.in/alexcesaro/quotedprintable.v3/reader.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
// Package quotedprintable implements quoted-printable encoding as specified by
|
||||
// RFC 2045.
|
||||
package quotedprintable
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Reader is a quoted-printable decoder.
|
||||
type Reader struct {
|
||||
br *bufio.Reader
|
||||
rerr error // last read error
|
||||
line []byte // to be consumed before more of br
|
||||
}
|
||||
|
||||
// NewReader returns a quoted-printable reader, decoding from r.
|
||||
func NewReader(r io.Reader) *Reader {
|
||||
return &Reader{
|
||||
br: bufio.NewReader(r),
|
||||
}
|
||||
}
|
||||
|
||||
func fromHex(b byte) (byte, error) {
|
||||
switch {
|
||||
case b >= '0' && b <= '9':
|
||||
return b - '0', nil
|
||||
case b >= 'A' && b <= 'F':
|
||||
return b - 'A' + 10, nil
|
||||
// Accept badly encoded bytes.
|
||||
case b >= 'a' && b <= 'f':
|
||||
return b - 'a' + 10, nil
|
||||
}
|
||||
return 0, fmt.Errorf("quotedprintable: invalid hex byte 0x%02x", b)
|
||||
}
|
||||
|
||||
func readHexByte(a, b byte) (byte, error) {
|
||||
var hb, lb byte
|
||||
var err error
|
||||
if hb, err = fromHex(a); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if lb, err = fromHex(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return hb<<4 | lb, nil
|
||||
}
|
||||
|
||||
func isQPDiscardWhitespace(r rune) bool {
|
||||
switch r {
|
||||
case '\n', '\r', ' ', '\t':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
crlf = []byte("\r\n")
|
||||
lf = []byte("\n")
|
||||
softSuffix = []byte("=")
|
||||
)
|
||||
|
||||
// Read reads and decodes quoted-printable data from the underlying reader.
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
// Deviations from RFC 2045:
|
||||
// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
|
||||
// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
|
||||
// with other broken QP encoders & decoders.
|
||||
for len(p) > 0 {
|
||||
if len(r.line) == 0 {
|
||||
if r.rerr != nil {
|
||||
return n, r.rerr
|
||||
}
|
||||
r.line, r.rerr = r.br.ReadSlice('\n')
|
||||
|
||||
// Does the line end in CRLF instead of just LF?
|
||||
hasLF := bytes.HasSuffix(r.line, lf)
|
||||
hasCR := bytes.HasSuffix(r.line, crlf)
|
||||
wholeLine := r.line
|
||||
r.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
|
||||
if bytes.HasSuffix(r.line, softSuffix) {
|
||||
rightStripped := wholeLine[len(r.line):]
|
||||
r.line = r.line[:len(r.line)-1]
|
||||
if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
|
||||
r.rerr = fmt.Errorf("quotedprintable: invalid bytes after =: %q", rightStripped)
|
||||
}
|
||||
} else if hasLF {
|
||||
if hasCR {
|
||||
r.line = append(r.line, '\r', '\n')
|
||||
} else {
|
||||
r.line = append(r.line, '\n')
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
b := r.line[0]
|
||||
|
||||
switch {
|
||||
case b == '=':
|
||||
if len(r.line[1:]) < 2 {
|
||||
return n, io.ErrUnexpectedEOF
|
||||
}
|
||||
b, err = readHexByte(r.line[1], r.line[2])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
r.line = r.line[2:] // 2 of the 3; other 1 is done below
|
||||
case b == '\t' || b == '\r' || b == '\n':
|
||||
break
|
||||
case b < ' ' || b > '~':
|
||||
return n, fmt.Errorf("quotedprintable: invalid unescaped byte 0x%02x in body", b)
|
||||
}
|
||||
p[0] = b
|
||||
p = p[1:]
|
||||
r.line = r.line[1:]
|
||||
n++
|
||||
}
|
||||
return n, nil
|
||||
}
|
166
vendor/gopkg.in/alexcesaro/quotedprintable.v3/writer.go
generated
vendored
Normal file
166
vendor/gopkg.in/alexcesaro/quotedprintable.v3/writer.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
package quotedprintable
|
||||
|
||||
import "io"
|
||||
|
||||
const lineMaxLen = 76
|
||||
|
||||
// A Writer is a quoted-printable writer that implements io.WriteCloser.
|
||||
type Writer struct {
|
||||
// Binary mode treats the writer's input as pure binary and processes end of
|
||||
// line bytes as binary data.
|
||||
Binary bool
|
||||
|
||||
w io.Writer
|
||||
i int
|
||||
line [78]byte
|
||||
cr bool
|
||||
}
|
||||
|
||||
// NewWriter returns a new Writer that writes to w.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
return &Writer{w: w}
|
||||
}
|
||||
|
||||
// Write encodes p using quoted-printable encoding and writes it to the
|
||||
// underlying io.Writer. It limits line length to 76 characters. The encoded
|
||||
// bytes are not necessarily flushed until the Writer is closed.
|
||||
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||
for i, b := range p {
|
||||
switch {
|
||||
// Simple writes are done in batch.
|
||||
case b >= '!' && b <= '~' && b != '=':
|
||||
continue
|
||||
case isWhitespace(b) || !w.Binary && (b == '\n' || b == '\r'):
|
||||
continue
|
||||
}
|
||||
|
||||
if i > n {
|
||||
if err := w.write(p[n:i]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n = i
|
||||
}
|
||||
|
||||
if err := w.encode(b); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n++
|
||||
}
|
||||
|
||||
if n == len(p) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
if err := w.write(p[n:]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Close closes the Writer, flushing any unwritten data to the underlying
|
||||
// io.Writer, but does not close the underlying io.Writer.
|
||||
func (w *Writer) Close() error {
|
||||
if err := w.checkLastByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return w.flush()
|
||||
}
|
||||
|
||||
// write limits text encoded in quoted-printable to 76 characters per line.
|
||||
func (w *Writer) write(p []byte) error {
|
||||
for _, b := range p {
|
||||
if b == '\n' || b == '\r' {
|
||||
// If the previous byte was \r, the CRLF has already been inserted.
|
||||
if w.cr && b == '\n' {
|
||||
w.cr = false
|
||||
continue
|
||||
}
|
||||
|
||||
if b == '\r' {
|
||||
w.cr = true
|
||||
}
|
||||
|
||||
if err := w.checkLastByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.insertCRLF(); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if w.i == lineMaxLen-1 {
|
||||
if err := w.insertSoftLineBreak(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
w.line[w.i] = b
|
||||
w.i++
|
||||
w.cr = false
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Writer) encode(b byte) error {
|
||||
if lineMaxLen-1-w.i < 3 {
|
||||
if err := w.insertSoftLineBreak(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
w.line[w.i] = '='
|
||||
w.line[w.i+1] = upperhex[b>>4]
|
||||
w.line[w.i+2] = upperhex[b&0x0f]
|
||||
w.i += 3
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkLastByte encodes the last buffered byte if it is a space or a tab.
|
||||
func (w *Writer) checkLastByte() error {
|
||||
if w.i == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
b := w.line[w.i-1]
|
||||
if isWhitespace(b) {
|
||||
w.i--
|
||||
if err := w.encode(b); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Writer) insertSoftLineBreak() error {
|
||||
w.line[w.i] = '='
|
||||
w.i++
|
||||
|
||||
return w.insertCRLF()
|
||||
}
|
||||
|
||||
func (w *Writer) insertCRLF() error {
|
||||
w.line[w.i] = '\r'
|
||||
w.line[w.i+1] = '\n'
|
||||
w.i += 2
|
||||
|
||||
return w.flush()
|
||||
}
|
||||
|
||||
func (w *Writer) flush() error {
|
||||
if _, err := w.w.Write(w.line[:w.i]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.i = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func isWhitespace(b byte) bool {
|
||||
return b == ' ' || b == '\t'
|
||||
}
|
Reference in New Issue
Block a user