137 lines
2.9 KiB
Go
137 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type Message struct {
|
|
Tags map[string]string
|
|
Source string
|
|
Command command
|
|
Parameters []string
|
|
Raw string
|
|
|
|
parseIndex int
|
|
}
|
|
|
|
func (m *Message) ParseMessage() error {
|
|
m.parseIndex = 0
|
|
m.consumeSpaces()
|
|
if m.consume('@') {
|
|
m.Tags, _ = m.parseTags()
|
|
}
|
|
m.consumeSpaces()
|
|
if m.consume(':') {
|
|
m.Source, _ = m.parseSource()
|
|
}
|
|
m.consumeSpaces()
|
|
m.Command, _ = m.parseCommand()
|
|
m.consumeSpaces()
|
|
m.Parameters, _ = m.parseParameters()
|
|
return nil
|
|
}
|
|
|
|
func (m *Message) parseTags() (map[string]string, error) {
|
|
tags := make(map[string]string)
|
|
for {
|
|
next := m.findNext("=", ";")
|
|
if next == -1 {
|
|
break
|
|
} else if m.Raw[m.parseIndex+next] == '=' {
|
|
key := m.Raw[m.parseIndex : m.parseIndex+next]
|
|
m.parseIndex += next + 1
|
|
eot := m.findNext(";", " ")
|
|
tags[key] = m.Raw[m.parseIndex : m.parseIndex+eot]
|
|
m.parseIndex += len(tags[key]) + 1
|
|
} else if m.Raw[m.parseIndex+next] == ';' {
|
|
key := m.Raw[m.parseIndex : m.parseIndex+next]
|
|
m.parseIndex += next + 1
|
|
tags[key] = ""
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return tags, nil
|
|
}
|
|
|
|
func (m *Message) parseSource() (string, error) {
|
|
start := m.parseIndex
|
|
endofparse := strings.Index(m.Raw[m.parseIndex:], " ")
|
|
if endofparse == -1 {
|
|
return "", fmt.Errorf("end of string encountered while parsing tags")
|
|
}
|
|
m.parseIndex += endofparse
|
|
return m.Raw[start:m.parseIndex], nil
|
|
}
|
|
|
|
func (m *Message) parseCommand() (command, error) {
|
|
start := m.parseIndex
|
|
endofparse := strings.Index(m.Raw[m.parseIndex:], " ")
|
|
if endofparse == -1 {
|
|
return "", fmt.Errorf("end of string encountered while parsing command")
|
|
}
|
|
m.parseIndex += endofparse
|
|
return command(m.Raw[start:m.parseIndex]), nil
|
|
}
|
|
|
|
func (m *Message) parseParameters() ([]string, error) {
|
|
params := []string{}
|
|
for m.parseIndex <= len(m.Raw) {
|
|
m.consumeSpaces()
|
|
if m.consume(':') { // "run until end of line"
|
|
params = append(params, m.Raw[m.parseIndex:])
|
|
break
|
|
}
|
|
endofparse := strings.Index(m.Raw[m.parseIndex:], " ")
|
|
if endofparse == -1 { // no further params after this one
|
|
p := strings.TrimSuffix(m.Raw[m.parseIndex:], " ")
|
|
if len(p) > 0 { // reject empty trailing params
|
|
params = append(params, p)
|
|
}
|
|
break
|
|
}
|
|
params = append(params, m.Raw[m.parseIndex:m.parseIndex+endofparse])
|
|
m.parseIndex += endofparse
|
|
}
|
|
return params, nil
|
|
}
|
|
|
|
func (m *Message) consumeSpaces() {
|
|
if len(m.Raw) <= m.parseIndex {
|
|
return
|
|
}
|
|
for len(m.Raw) > m.parseIndex && m.Raw[m.parseIndex] == ' ' {
|
|
m.parseIndex++
|
|
}
|
|
}
|
|
|
|
func (m *Message) consume(r byte) bool {
|
|
if len(m.Raw) <= m.parseIndex {
|
|
return false
|
|
}
|
|
if m.Raw[m.parseIndex] == r {
|
|
m.parseIndex++
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (m *Message) findNext(bs ...string) int {
|
|
if len(bs) == 0 {
|
|
return 0
|
|
}
|
|
r := -1
|
|
for _, b := range bs {
|
|
i := strings.Index(m.Raw[m.parseIndex:], b)
|
|
if r == -1 || (i != -1 && i < r) {
|
|
r = i
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
func (m *Message) ToBytes() []byte {
|
|
return nil
|
|
}
|