1
2
3
4
5
6
7
8
9 package dict
10
11 import (
12 "net/textproto"
13 "strconv"
14 "strings"
15 )
16
17
18 type Client struct {
19 text *textproto.Conn
20 }
21
22
23
24 func Dial(network, addr string) (*Client, error) {
25 text, err := textproto.Dial(network, addr)
26 if err != nil {
27 return nil, err
28 }
29 _, _, err = text.ReadCodeLine(220)
30 if err != nil {
31 text.Close()
32 return nil, err
33 }
34 return &Client{text: text}, nil
35 }
36
37
38 func (c *Client) Close() error {
39 return c.text.Close()
40 }
41
42
43 type Dict struct {
44 Name string
45 Desc string
46 }
47
48
49 func (c *Client) Dicts() ([]Dict, error) {
50 id, err := c.text.Cmd("SHOW DB")
51 if err != nil {
52 return nil, err
53 }
54
55 c.text.StartResponse(id)
56 defer c.text.EndResponse(id)
57
58 _, _, err = c.text.ReadCodeLine(110)
59 if err != nil {
60 return nil, err
61 }
62 lines, err := c.text.ReadDotLines()
63 if err != nil {
64 return nil, err
65 }
66 _, _, err = c.text.ReadCodeLine(250)
67
68 dicts := make([]Dict, len(lines))
69 for i := range dicts {
70 d := &dicts[i]
71 a, _ := fields(lines[i])
72 if len(a) < 2 {
73 return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
74 }
75 d.Name = a[0]
76 d.Desc = a[1]
77 }
78 return dicts, err
79 }
80
81
82 type Defn struct {
83 Dict Dict
84 Word string
85 Text []byte
86 }
87
88
89
90
91
92
93
94
95
96
97 func (c *Client) Define(dict, word string) ([]*Defn, error) {
98 id, err := c.text.Cmd("DEFINE %s %q", dict, word)
99 if err != nil {
100 return nil, err
101 }
102
103 c.text.StartResponse(id)
104 defer c.text.EndResponse(id)
105
106 _, line, err := c.text.ReadCodeLine(150)
107 if err != nil {
108 return nil, err
109 }
110 a, _ := fields(line)
111 if len(a) < 1 {
112 return nil, textproto.ProtocolError("malformed response: " + line)
113 }
114 n, err := strconv.Atoi(a[0])
115 if err != nil {
116 return nil, textproto.ProtocolError("invalid definition count: " + a[0])
117 }
118 def := make([]*Defn, n)
119 for i := 0; i < n; i++ {
120 _, line, err = c.text.ReadCodeLine(151)
121 if err != nil {
122 return nil, err
123 }
124 a, _ := fields(line)
125 if len(a) < 3 {
126
127 i--
128 n--
129 def = def[0:n]
130 continue
131 }
132 d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
133 d.Text, err = c.text.ReadDotBytes()
134 if err != nil {
135 return nil, err
136 }
137 def[i] = d
138 }
139 _, _, err = c.text.ReadCodeLine(250)
140 return def, err
141 }
142
143
144
145
146 func fields(s string) ([]string, error) {
147 var v []string
148 i := 0
149 for {
150 for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
151 i++
152 }
153 if i >= len(s) {
154 break
155 }
156 if s[i] == '"' || s[i] == '\'' {
157 q := s[i]
158
159 var j int
160 for j = i + 1; ; j++ {
161 if j >= len(s) {
162 return nil, textproto.ProtocolError("malformed quoted string")
163 }
164 if s[j] == '\\' {
165 j++
166 continue
167 }
168 if s[j] == q {
169 j++
170 break
171 }
172 }
173 v = append(v, unquote(s[i+1:j-1]))
174 i = j
175 } else {
176
177 var j int
178 for j = i; j < len(s); j++ {
179 if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
180 break
181 }
182 }
183 v = append(v, s[i:j])
184 i = j
185 }
186 if i < len(s) {
187 c := s[i]
188 if c != ' ' && c != '\t' {
189 return nil, textproto.ProtocolError("quotes not on word boundaries")
190 }
191 }
192 }
193 return v, nil
194 }
195
196 func unquote(s string) string {
197 if strings.Index(s, "\\") < 0 {
198 return s
199 }
200 b := []byte(s)
201 w := 0
202 for r := 0; r < len(b); r++ {
203 c := b[r]
204 if c == '\\' {
205 r++
206 c = b[r]
207 }
208 b[w] = c
209 w++
210 }
211 return string(b[0:w])
212 }
213
View as plain text