1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
package stmt
import (
"unicode"
"github.com/xo/usql/text"
)
// Params holds information about command parameters.
type Params struct {
R []rune
Len int
}
// DecodeParams decodes command parameters.
func DecodeParams(params string) *Params {
r := []rune(params)
return &Params{
R: r,
Len: len(r),
}
}
// GetRaw reads all remaining runes. No substitution or whitespace removal is
// performed.
func (p *Params) GetRaw() string {
s := string(p.R)
p.R, p.Len = p.R[:0], 0
return s
}
// Get reads the next command parameter using the provided substitution func.
// True indicates there are runes remaining in the command parameters to
// process.
func (p *Params) Get(f func(string, bool) (bool, string, error)) (bool, string, error) {
i, _ := findNonSpace(p.R, 0, p.Len)
if i >= p.Len {
return false, "", nil
}
var ok bool
var quote rune
start := i
loop:
for ; i < p.Len; i++ {
c, next := p.R[i], grab(p.R, i+1, p.Len)
switch {
case quote != 0:
start := i - 1
i, ok = readString(p.R, i, p.Len, quote, "")
if !ok {
break loop
}
ok, z, err := f(string(p.R[start:i+1]), false)
switch {
case err != nil:
return false, "", err
case ok:
p.R, p.Len = substitute(p.R, start, p.Len, i-start+1, z)
i = start + len(z) - 1
}
quote = 0
// start of single, double, or backtick string
case c == '\'' || c == '"' || c == '`':
quote = c
case c == ':' && next != ':':
if v := readVar(p.R, i, p.Len); v != nil {
n := v.String()
ok, z, err := f(n[1:], true)
switch {
case err != nil:
return false, "", err
case ok:
p.R, p.Len = substitute(p.R, v.I, p.Len, len(n), z)
i = v.I + len(z) - 1
default:
i += len(n) - 1
}
}
case unicode.IsSpace(c):
break loop
}
}
if quote != 0 {
return false, "", text.ErrUnterminatedQuotedString
}
v := string(p.R[start:i])
p.R = p.R[i:]
p.Len = len(p.R)
return true, v, nil
}
// GetAll retrieves all remaining command parameters using the provided
// substitution func. Will return on the first encountered error.
func (p *Params) GetAll(f func(string, bool) (bool, string, error)) ([]string, error) {
var s []string
for {
ok, v, err := p.Get(f)
if err != nil {
return s, err
}
if !ok {
break
}
s = append(s, v)
}
return s, nil
}
|