OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / dict / dict.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 dict implements the Dictionary Server Protocol
6 // as defined in RFC 2229.
7 package dict // import "golang.org/x/net/dict"
8
9 import (
10         "net/textproto"
11         "strconv"
12         "strings"
13 )
14
15 // A Client represents a client connection to a dictionary server.
16 type Client struct {
17         text *textproto.Conn
18 }
19
20 // Dial returns a new client connected to a dictionary server at
21 // addr on the given network.
22 func Dial(network, addr string) (*Client, error) {
23         text, err := textproto.Dial(network, addr)
24         if err != nil {
25                 return nil, err
26         }
27         _, _, err = text.ReadCodeLine(220)
28         if err != nil {
29                 text.Close()
30                 return nil, err
31         }
32         return &Client{text: text}, nil
33 }
34
35 // Close closes the connection to the dictionary server.
36 func (c *Client) Close() error {
37         return c.text.Close()
38 }
39
40 // A Dict represents a dictionary available on the server.
41 type Dict struct {
42         Name string // short name of dictionary
43         Desc string // long description
44 }
45
46 // Dicts returns a list of the dictionaries available on the server.
47 func (c *Client) Dicts() ([]Dict, error) {
48         id, err := c.text.Cmd("SHOW DB")
49         if err != nil {
50                 return nil, err
51         }
52
53         c.text.StartResponse(id)
54         defer c.text.EndResponse(id)
55
56         _, _, err = c.text.ReadCodeLine(110)
57         if err != nil {
58                 return nil, err
59         }
60         lines, err := c.text.ReadDotLines()
61         if err != nil {
62                 return nil, err
63         }
64         _, _, err = c.text.ReadCodeLine(250)
65
66         dicts := make([]Dict, len(lines))
67         for i := range dicts {
68                 d := &dicts[i]
69                 a, _ := fields(lines[i])
70                 if len(a) < 2 {
71                         return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
72                 }
73                 d.Name = a[0]
74                 d.Desc = a[1]
75         }
76         return dicts, err
77 }
78
79 // A Defn represents a definition.
80 type Defn struct {
81         Dict Dict   // Dict where definition was found
82         Word string // Word being defined
83         Text []byte // Definition text, typically multiple lines
84 }
85
86 // Define requests the definition of the given word.
87 // The argument dict names the dictionary to use,
88 // the Name field of a Dict returned by Dicts.
89 //
90 // The special dictionary name "*" means to look in all the
91 // server's dictionaries.
92 // The special dictionary name "!" means to look in all the
93 // server's dictionaries in turn, stopping after finding the word
94 // in one of them.
95 func (c *Client) Define(dict, word string) ([]*Defn, error) {
96         id, err := c.text.Cmd("DEFINE %s %q", dict, word)
97         if err != nil {
98                 return nil, err
99         }
100
101         c.text.StartResponse(id)
102         defer c.text.EndResponse(id)
103
104         _, line, err := c.text.ReadCodeLine(150)
105         if err != nil {
106                 return nil, err
107         }
108         a, _ := fields(line)
109         if len(a) < 1 {
110                 return nil, textproto.ProtocolError("malformed response: " + line)
111         }
112         n, err := strconv.Atoi(a[0])
113         if err != nil {
114                 return nil, textproto.ProtocolError("invalid definition count: " + a[0])
115         }
116         def := make([]*Defn, n)
117         for i := 0; i < n; i++ {
118                 _, line, err = c.text.ReadCodeLine(151)
119                 if err != nil {
120                         return nil, err
121                 }
122                 a, _ := fields(line)
123                 if len(a) < 3 {
124                         // skip it, to keep protocol in sync
125                         i--
126                         n--
127                         def = def[0:n]
128                         continue
129                 }
130                 d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
131                 d.Text, err = c.text.ReadDotBytes()
132                 if err != nil {
133                         return nil, err
134                 }
135                 def[i] = d
136         }
137         _, _, err = c.text.ReadCodeLine(250)
138         return def, err
139 }
140
141 // Fields returns the fields in s.
142 // Fields are space separated unquoted words
143 // or quoted with single or double quote.
144 func fields(s string) ([]string, error) {
145         var v []string
146         i := 0
147         for {
148                 for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
149                         i++
150                 }
151                 if i >= len(s) {
152                         break
153                 }
154                 if s[i] == '"' || s[i] == '\'' {
155                         q := s[i]
156                         // quoted string
157                         var j int
158                         for j = i + 1; ; j++ {
159                                 if j >= len(s) {
160                                         return nil, textproto.ProtocolError("malformed quoted string")
161                                 }
162                                 if s[j] == '\\' {
163                                         j++
164                                         continue
165                                 }
166                                 if s[j] == q {
167                                         j++
168                                         break
169                                 }
170                         }
171                         v = append(v, unquote(s[i+1:j-1]))
172                         i = j
173                 } else {
174                         // atom
175                         var j int
176                         for j = i; j < len(s); j++ {
177                                 if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
178                                         break
179                                 }
180                         }
181                         v = append(v, s[i:j])
182                         i = j
183                 }
184                 if i < len(s) {
185                         c := s[i]
186                         if c != ' ' && c != '\t' {
187                                 return nil, textproto.ProtocolError("quotes not on word boundaries")
188                         }
189                 }
190         }
191         return v, nil
192 }
193
194 func unquote(s string) string {
195         if strings.Index(s, "\\") < 0 {
196                 return s
197         }
198         b := []byte(s)
199         w := 0
200         for r := 0; r < len(b); r++ {
201                 c := b[r]
202                 if c == '\\' {
203                         r++
204                         c = b[r]
205                 }
206                 b[w] = c
207                 w++
208         }
209         return string(b[0:w])
210 }