...
  
  
     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