forked from jshiffer/matterbridge
108 lines
1.8 KiB
Go
108 lines
1.8 KiB
Go
|
package strftime
|
||
|
|
||
|
import "unicode/utf8"
|
||
|
|
||
|
type parser struct {
|
||
|
format func(spec, flag byte) error
|
||
|
literal func(byte) error
|
||
|
}
|
||
|
|
||
|
func (p *parser) parse(fmt string) error {
|
||
|
const (
|
||
|
initial = iota
|
||
|
percent
|
||
|
flagged
|
||
|
modified
|
||
|
)
|
||
|
|
||
|
var flag, modifier byte
|
||
|
var err error
|
||
|
state := initial
|
||
|
start := 0
|
||
|
for i, b := range []byte(fmt) {
|
||
|
switch state {
|
||
|
default:
|
||
|
if b == '%' {
|
||
|
state = percent
|
||
|
start = i
|
||
|
continue
|
||
|
}
|
||
|
err = p.literal(b)
|
||
|
|
||
|
case percent:
|
||
|
if b == '-' || b == ':' {
|
||
|
state = flagged
|
||
|
flag = b
|
||
|
continue
|
||
|
}
|
||
|
if b == 'E' || b == 'O' {
|
||
|
state = modified
|
||
|
modifier = b
|
||
|
flag = 0
|
||
|
continue
|
||
|
}
|
||
|
err = p.format(b, 0)
|
||
|
state = initial
|
||
|
|
||
|
case flagged:
|
||
|
if b == 'E' || b == 'O' {
|
||
|
state = modified
|
||
|
modifier = b
|
||
|
continue
|
||
|
}
|
||
|
err = p.format(b, flag)
|
||
|
state = initial
|
||
|
|
||
|
case modified:
|
||
|
if okModifier(modifier, b) {
|
||
|
err = p.format(b, flag)
|
||
|
} else {
|
||
|
err = p.literals(fmt[start : i+1])
|
||
|
}
|
||
|
state = initial
|
||
|
}
|
||
|
|
||
|
if err != nil {
|
||
|
if err, ok := err.(formatError); ok {
|
||
|
err.setDirective(fmt, start, i)
|
||
|
return err
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if state != initial {
|
||
|
return p.literals(fmt[start:])
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (p *parser) literals(literal string) error {
|
||
|
for _, b := range []byte(literal) {
|
||
|
if err := p.literal(b); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type literalErr string
|
||
|
|
||
|
func (e literalErr) Error() string {
|
||
|
return "strftime: unsupported literal: " + string(e)
|
||
|
}
|
||
|
|
||
|
type formatError struct {
|
||
|
message string
|
||
|
directive string
|
||
|
}
|
||
|
|
||
|
func (e formatError) Error() string {
|
||
|
return "strftime: unsupported directive: " + e.directive + " " + e.message
|
||
|
}
|
||
|
|
||
|
func (e *formatError) setDirective(str string, i, j int) {
|
||
|
_, n := utf8.DecodeRuneInString(str[j:])
|
||
|
e.directive = str[i : j+n]
|
||
|
}
|