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 dict implements the Dictionary Server Protocol
6 // as defined in RFC 2229.
7 package dict // import "golang.org/x/net/dict"
15 // A Client represents a client connection to a dictionary server.
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)
27 _, _, err = text.ReadCodeLine(220)
32 return &Client{text: text}, nil
35 // Close closes the connection to the dictionary server.
36 func (c *Client) Close() error {
40 // A Dict represents a dictionary available on the server.
42 Name string // short name of dictionary
43 Desc string // long description
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")
53 c.text.StartResponse(id)
54 defer c.text.EndResponse(id)
56 _, _, err = c.text.ReadCodeLine(110)
60 lines, err := c.text.ReadDotLines()
64 _, _, err = c.text.ReadCodeLine(250)
66 dicts := make([]Dict, len(lines))
67 for i := range dicts {
69 a, _ := fields(lines[i])
71 return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
79 // A Defn represents a definition.
81 Dict Dict // Dict where definition was found
82 Word string // Word being defined
83 Text []byte // Definition text, typically multiple lines
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.
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
95 func (c *Client) Define(dict, word string) ([]*Defn, error) {
96 id, err := c.text.Cmd("DEFINE %s %q", dict, word)
101 c.text.StartResponse(id)
102 defer c.text.EndResponse(id)
104 _, line, err := c.text.ReadCodeLine(150)
110 return nil, textproto.ProtocolError("malformed response: " + line)
112 n, err := strconv.Atoi(a[0])
114 return nil, textproto.ProtocolError("invalid definition count: " + a[0])
116 def := make([]*Defn, n)
117 for i := 0; i < n; i++ {
118 _, line, err = c.text.ReadCodeLine(151)
124 // skip it, to keep protocol in sync
130 d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
131 d.Text, err = c.text.ReadDotBytes()
137 _, _, err = c.text.ReadCodeLine(250)
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) {
148 for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
154 if s[i] == '"' || s[i] == '\'' {
158 for j = i + 1; ; j++ {
160 return nil, textproto.ProtocolError("malformed quoted string")
171 v = append(v, unquote(s[i+1:j-1]))
176 for j = i; j < len(s); j++ {
177 if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
181 v = append(v, s[i:j])
186 if c != ' ' && c != '\t' {
187 return nil, textproto.ProtocolError("quotes not on word boundaries")
194 func unquote(s string) string {
195 if strings.Index(s, "\\") < 0 {
200 for r := 0; r < len(b); r++ {
209 return string(b[0:w])