libgo: update to Go 1.11
[official-gcc.git] / libgo / go / encoding / json / indent.go
blobfba19548c92721d2f2fb0c63dd3accaa8a3077d3
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 json
7 import "bytes"
9 // Compact appends to dst the JSON-encoded src with
10 // insignificant space characters elided.
11 func Compact(dst *bytes.Buffer, src []byte) error {
12 return compact(dst, src, false)
15 func compact(dst *bytes.Buffer, src []byte, escape bool) error {
16 origLen := dst.Len()
17 var scan scanner
18 scan.reset()
19 start := 0
20 for i, c := range src {
21 if escape && (c == '<' || c == '>' || c == '&') {
22 if start < i {
23 dst.Write(src[start:i])
25 dst.WriteString(`\u00`)
26 dst.WriteByte(hex[c>>4])
27 dst.WriteByte(hex[c&0xF])
28 start = i + 1
30 // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
31 if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
32 if start < i {
33 dst.Write(src[start:i])
35 dst.WriteString(`\u202`)
36 dst.WriteByte(hex[src[i+2]&0xF])
37 start = i + 3
39 v := scan.step(&scan, c)
40 if v >= scanSkipSpace {
41 if v == scanError {
42 break
44 if start < i {
45 dst.Write(src[start:i])
47 start = i + 1
50 if scan.eof() == scanError {
51 dst.Truncate(origLen)
52 return scan.err
54 if start < len(src) {
55 dst.Write(src[start:])
57 return nil
60 func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
61 dst.WriteByte('\n')
62 dst.WriteString(prefix)
63 for i := 0; i < depth; i++ {
64 dst.WriteString(indent)
68 // Indent appends to dst an indented form of the JSON-encoded src.
69 // Each element in a JSON object or array begins on a new,
70 // indented line beginning with prefix followed by one or more
71 // copies of indent according to the indentation nesting.
72 // The data appended to dst does not begin with the prefix nor
73 // any indentation, to make it easier to embed inside other formatted JSON data.
74 // Although leading space characters (space, tab, carriage return, newline)
75 // at the beginning of src are dropped, trailing space characters
76 // at the end of src are preserved and copied to dst.
77 // For example, if src has no trailing spaces, neither will dst;
78 // if src ends in a trailing newline, so will dst.
79 func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
80 origLen := dst.Len()
81 var scan scanner
82 scan.reset()
83 needIndent := false
84 depth := 0
85 for _, c := range src {
86 scan.bytes++
87 v := scan.step(&scan, c)
88 if v == scanSkipSpace {
89 continue
91 if v == scanError {
92 break
94 if needIndent && v != scanEndObject && v != scanEndArray {
95 needIndent = false
96 depth++
97 newline(dst, prefix, indent, depth)
100 // Emit semantically uninteresting bytes
101 // (in particular, punctuation in strings) unmodified.
102 if v == scanContinue {
103 dst.WriteByte(c)
104 continue
107 // Add spacing around real punctuation.
108 switch c {
109 case '{', '[':
110 // delay indent so that empty object and array are formatted as {} and [].
111 needIndent = true
112 dst.WriteByte(c)
114 case ',':
115 dst.WriteByte(c)
116 newline(dst, prefix, indent, depth)
118 case ':':
119 dst.WriteByte(c)
120 dst.WriteByte(' ')
122 case '}', ']':
123 if needIndent {
124 // suppress indent in empty object/array
125 needIndent = false
126 } else {
127 depth--
128 newline(dst, prefix, indent, depth)
130 dst.WriteByte(c)
132 default:
133 dst.WriteByte(c)
136 if scan.eof() == scanError {
137 dst.Truncate(origLen)
138 return scan.err
140 return nil