OSDN Git Service

Update Go library to last weekly.
[pf3gnuchains/gcc-fork.git] / libgo / go / json / indent.go
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.
4
5 package json
6
7 import (
8         "bytes"
9         "os"
10 )
11
12 // Compact appends to dst the JSON-encoded src with
13 // insignificant space characters elided.
14 func Compact(dst *bytes.Buffer, src []byte) os.Error {
15         origLen := dst.Len()
16         var scan scanner
17         scan.reset()
18         start := 0
19         for i, c := range src {
20                 v := scan.step(&scan, int(c))
21                 if v >= scanSkipSpace {
22                         if v == scanError {
23                                 break
24                         }
25                         if start < i {
26                                 dst.Write(src[start:i])
27                         }
28                         start = i + 1
29                 }
30         }
31         if scan.eof() == scanError {
32                 dst.Truncate(origLen)
33                 return scan.err
34         }
35         if start < len(src) {
36                 dst.Write(src[start:])
37         }
38         return nil
39 }
40
41 func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
42         dst.WriteByte('\n')
43         dst.WriteString(prefix)
44         for i := 0; i < depth; i++ {
45                 dst.WriteString(indent)
46         }
47 }
48
49 // Indent appends to dst an indented form of the JSON-encoded src.
50 // Each element in a JSON object or array begins on a new,
51 // indented line beginning with prefix followed by one or more
52 // copies of indent according to the indentation nesting.
53 // The data appended to dst has no trailing newline, to make it easier
54 // to embed inside other formatted JSON data.
55 func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error {
56         origLen := dst.Len()
57         var scan scanner
58         scan.reset()
59         needIndent := false
60         depth := 0
61         for _, c := range src {
62                 scan.bytes++
63                 v := scan.step(&scan, int(c))
64                 if v == scanSkipSpace {
65                         continue
66                 }
67                 if v == scanError {
68                         break
69                 }
70                 if needIndent && v != scanEndObject && v != scanEndArray {
71                         needIndent = false
72                         depth++
73                         newline(dst, prefix, indent, depth)
74                 }
75
76                 // Emit semantically uninteresting bytes
77                 // (in particular, punctuation in strings) unmodified.
78                 if v == scanContinue {
79                         dst.WriteByte(c)
80                         continue
81                 }
82
83                 // Add spacing around real punctuation.
84                 switch c {
85                 case '{', '[':
86                         // delay indent so that empty object and array are formatted as {} and [].
87                         needIndent = true
88                         dst.WriteByte(c)
89
90                 case ',':
91                         dst.WriteByte(c)
92                         newline(dst, prefix, indent, depth)
93
94                 case ':':
95                         dst.WriteByte(c)
96                         dst.WriteByte(' ')
97
98                 case '}', ']':
99                         if needIndent {
100                                 // suppress indent in empty object/array
101                                 needIndent = false
102                         } else {
103                                 depth--
104                                 newline(dst, prefix, indent, depth)
105                         }
106                         dst.WriteByte(c)
107
108                 default:
109                         dst.WriteByte(c)
110                 }
111         }
112         if scan.eof() == scanError {
113                 dst.Truncate(origLen)
114                 return scan.err
115         }
116         return nil
117 }