...
1
2
3
4
5 package catmsg
6
7 import (
8 "errors"
9 "fmt"
10
11 "golang.org/x/text/language"
12 )
13
14
15 type Renderer interface {
16
17
18 Render(s string)
19
20
21
22
23
24 Arg(i int) interface{}
25 }
26
27
28 type Dictionary interface {
29
30
31 Lookup(key string) (data string, ok bool)
32
33
34
35 }
36
37
38 type Encoder struct {
39
40 root *Encoder
41
42
43 parent *Encoder
44
45 tag language.Tag
46
47
48
49
50 buf []byte
51
52
53 vars []keyVal
54
55 err error
56 inBody bool
57 }
58
59 type keyVal struct {
60 key string
61 offset int
62 }
63
64
65
66 func (e *Encoder) Language() language.Tag { return e.tag }
67
68 func (e *Encoder) setError(err error) {
69 if e.root.err == nil {
70 e.root.err = err
71 }
72 }
73
74
75 func (e *Encoder) EncodeUint(x uint64) {
76 e.checkInBody()
77 var buf [maxVarintBytes]byte
78 n := encodeUint(buf[:], x)
79 e.buf = append(e.buf, buf[:n]...)
80 }
81
82
83 func (e *Encoder) EncodeString(s string) {
84 e.checkInBody()
85 e.EncodeUint(uint64(len(s)))
86 e.buf = append(e.buf, s...)
87 }
88
89
90
91
92 func (e *Encoder) EncodeMessageType(h Handle) {
93 if e.inBody {
94 panic("catmsg: EncodeMessageType not the first method called")
95 }
96 e.inBody = true
97 e.EncodeUint(uint64(h))
98 }
99
100
101 func (e *Encoder) EncodeMessage(m Message) error {
102 e = &Encoder{root: e.root, parent: e, tag: e.tag}
103 err := m.Compile(e)
104 if _, ok := m.(*Var); !ok {
105 e.flushTo(e.parent)
106 }
107 return err
108 }
109
110 func (e *Encoder) checkInBody() {
111 if !e.inBody {
112 panic("catmsg: expected prior call to EncodeMessageType")
113 }
114 }
115
116
117
118
119
120 func stripPrefix(b []byte) (n int) {
121 if len(b) > 0 && Handle(b[0]) == msgFirst {
122 x, n, _ := decodeUint(b[1:])
123 if 1+n+int(x) == len(b) {
124 return 1 + n
125 }
126 }
127 return 0
128 }
129
130 func (e *Encoder) flushTo(dst *Encoder) {
131 data := e.buf
132 p := stripPrefix(data)
133 if p > 0 {
134 data = data[1:]
135 } else {
136
137 dst.EncodeUint(uint64(len(data)))
138 }
139 dst.buf = append(dst.buf, data...)
140 }
141
142 func (e *Encoder) addVar(key string, m Message) error {
143 for _, v := range e.parent.vars {
144 if v.key == key {
145 err := fmt.Errorf("catmsg: duplicate variable %q", key)
146 e.setError(err)
147 return err
148 }
149 }
150 scope := e.parent
151
152
153
154
155 err := m.Compile(e)
156 if err != ErrIncomplete {
157 e.setError(err)
158 }
159 switch {
160 case len(e.buf) == 1 && Handle(e.buf[0]) == msgFirst:
161 e.buf = e.buf[:0]
162 e.inBody = false
163 fallthrough
164 case len(e.buf) == 0:
165
166 if err := String(key).Compile(e); err != nil {
167 e.setError(err)
168 }
169 case err == ErrIncomplete:
170 if Handle(e.buf[0]) != msgFirst {
171 seq := &Encoder{root: e.root, parent: e}
172 seq.EncodeMessageType(msgFirst)
173 e.flushTo(seq)
174 e = seq
175 }
176
177 e.EncodeMessage(String(key))
178 }
179
180
181 offset := len(e.root.buf)
182 e.flushTo(e.root)
183 e.buf = e.buf[:0]
184
185
186 scope.vars = append(scope.vars, keyVal{key: key, offset: offset})
187 return err
188 }
189
190 const (
191 substituteVar = iota
192 substituteMacro
193 substituteError
194 )
195
196
197
198
199
200 func (e *Encoder) EncodeSubstitution(name string, arguments ...int) {
201 if arity := len(arguments); arity > 0 {
202
203 e.EncodeUint(substituteMacro)
204 e.EncodeString(name)
205 for _, a := range arguments {
206 e.EncodeUint(uint64(a))
207 }
208 return
209 }
210 for scope := e; scope != nil; scope = scope.parent {
211 for _, v := range scope.vars {
212 if v.key != name {
213 continue
214 }
215 e.EncodeUint(substituteVar)
216 e.EncodeUint(uint64(v.offset))
217 return
218 }
219 }
220
221 e.EncodeUint(substituteError)
222 e.EncodeString(name)
223 e.setError(fmt.Errorf("catmsg: unknown var %q", name))
224 }
225
226
227 type Decoder struct {
228 tag language.Tag
229 dst Renderer
230 macros Dictionary
231
232 err error
233 vars string
234 data string
235
236 macroArg int
237 }
238
239
240
241
242
243 func NewDecoder(tag language.Tag, r Renderer, macros Dictionary) *Decoder {
244 return &Decoder{
245 tag: tag,
246 dst: r,
247 macros: macros,
248 }
249 }
250
251 func (d *Decoder) setError(err error) {
252 if d.err == nil {
253 d.err = err
254 }
255 }
256
257
258
259
260
261
262 func (d *Decoder) Language() language.Tag { return d.tag }
263
264
265 func (d *Decoder) Done() bool { return len(d.data) == 0 }
266
267
268 func (d *Decoder) Render(s string) { d.dst.Render(s) }
269
270
271
272
273
274 func (d *Decoder) Arg(i int) interface{} {
275 if d.macroArg != 0 {
276 if i != 1 {
277 panic("catmsg: only macros with single argument supported")
278 }
279 i = d.macroArg
280 }
281 return d.dst.Arg(i)
282 }
283
284
285
286 func (d *Decoder) DecodeUint() uint64 {
287 x, n, err := decodeUintString(d.data)
288 d.data = d.data[n:]
289 if err != nil {
290 d.setError(err)
291 }
292 return x
293 }
294
295
296
297 func (d *Decoder) DecodeString() string {
298 size := d.DecodeUint()
299 s := d.data[:size]
300 d.data = d.data[size:]
301 return s
302 }
303
304
305
306 func (d *Decoder) SkipMessage() {
307 n := int(d.DecodeUint())
308 d.data = d.data[n:]
309 }
310
311
312
313
314 func (d *Decoder) Execute(msg string) error {
315 d.err = nil
316 if !d.execute(msg) {
317 return ErrNoMatch
318 }
319 return d.err
320 }
321
322 func (d *Decoder) execute(msg string) bool {
323 saved := d.data
324 d.data = msg
325 ok := d.executeMessage()
326 d.data = saved
327 return ok
328 }
329
330
331
332
333
334 func (d *Decoder) executeMessageFromData(s string) (n int, ok bool) {
335 saved := d.data
336 d.data = s
337 size := int(d.DecodeUint())
338 n = len(s) - len(d.data)
339
340
341 d.data = d.data[:size]
342 ok = d.executeMessage()
343 n += size - len(d.data)
344 d.data = saved
345 return n, ok
346 }
347
348 var errUnknownHandler = errors.New("catmsg: string contains unsupported handler")
349
350
351
352 func (d *Decoder) executeMessage() bool {
353 if d.Done() {
354
355 return true
356 }
357 handle := d.DecodeUint()
358
359 var fn Handler
360 mutex.Lock()
361 if int(handle) < len(handlers) {
362 fn = handlers[handle]
363 }
364 mutex.Unlock()
365 if fn == nil {
366 d.setError(errUnknownHandler)
367 d.execute(fmt.Sprintf("\x02$!(UNKNOWNMSGHANDLER=%#x)", handle))
368 return true
369 }
370 return fn(d)
371 }
372
373
374 func (d *Decoder) ExecuteMessage() bool {
375 n, ok := d.executeMessageFromData(d.data)
376 d.data = d.data[n:]
377 return ok
378 }
379
380
381
382 func (d *Decoder) ExecuteSubstitution() {
383 switch x := d.DecodeUint(); x {
384 case substituteVar:
385 offset := d.DecodeUint()
386 d.executeMessageFromData(d.vars[offset:])
387 case substituteMacro:
388 name := d.DecodeString()
389 data, ok := d.macros.Lookup(name)
390 old := d.macroArg
391
392 d.macroArg = int(d.DecodeUint())
393 switch {
394 case !ok:
395
396 d.setError(fmt.Errorf("catmsg: undefined macro %q", name))
397 fallthrough
398 case !d.execute(data):
399 d.dst.Render(name)
400 }
401 d.macroArg = old
402 case substituteError:
403 d.dst.Render(d.DecodeString())
404 default:
405 panic("catmsg: unreachable")
406 }
407 }
408
View as plain text