Update cosiner/argv to v0.1.0 (#2088)
This commit is contained in:
parent
99369f99f8
commit
b14182324d
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module github.com/go-delve/delve
|
|||||||
go 1.11
|
go 1.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cosiner/argv v0.0.0-20170225145430-13bacc38a0a5
|
github.com/cosiner/argv v0.1.0
|
||||||
github.com/cpuguy83/go-md2man v1.0.10 // indirect
|
github.com/cpuguy83/go-md2man v1.0.10 // indirect
|
||||||
github.com/creack/pty v1.1.9
|
github.com/creack/pty v1.1.9
|
||||||
github.com/google/go-dap v0.2.0
|
github.com/google/go-dap v0.2.0
|
||||||
|
2
go.sum
2
go.sum
@ -1,5 +1,7 @@
|
|||||||
github.com/cosiner/argv v0.0.0-20170225145430-13bacc38a0a5 h1:rIXlvz2IWiupMFlC45cZCXZFvKX/ExBcSLrDy2G0Lp8=
|
github.com/cosiner/argv v0.0.0-20170225145430-13bacc38a0a5 h1:rIXlvz2IWiupMFlC45cZCXZFvKX/ExBcSLrDy2G0Lp8=
|
||||||
github.com/cosiner/argv v0.0.0-20170225145430-13bacc38a0a5/go.mod h1:p/NrK5tF6ICIly4qwEDsf6VDirFiWWz0FenfYBwJaKQ=
|
github.com/cosiner/argv v0.0.0-20170225145430-13bacc38a0a5/go.mod h1:p/NrK5tF6ICIly4qwEDsf6VDirFiWWz0FenfYBwJaKQ=
|
||||||
|
github.com/cosiner/argv v0.1.0 h1:BVDiEL32lwHukgJKP87btEPenzrrHUjajs/8yzaqcXg=
|
||||||
|
github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
|
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
|
||||||
|
@ -1043,10 +1043,11 @@ func parseNewArgv(args string) (resetArgs bool, newArgv []string, err error) {
|
|||||||
if args == "" {
|
if args == "" {
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
v, err := argv.Argv([]rune(args), argv.ParseEnv(os.Environ()),
|
v, err := argv.Argv(args,
|
||||||
func(s []rune, _ map[string]string) ([]rune, error) {
|
func(s string) (string, error) {
|
||||||
return nil, fmt.Errorf("Backtick not supported in '%s'", string(s))
|
return "", fmt.Errorf("Backtick not supported in '%s'", s)
|
||||||
})
|
},
|
||||||
|
nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
|
4
vendor/github.com/cosiner/argv/README.md
generated
vendored
4
vendor/github.com/cosiner/argv/README.md
generated
vendored
@ -13,7 +13,7 @@ Documentation can be found at [Godoc](https://godoc.org/github.com/cosiner/argv)
|
|||||||
# Example
|
# Example
|
||||||
```Go
|
```Go
|
||||||
func TestArgv(t *testing.T) {
|
func TestArgv(t *testing.T) {
|
||||||
args, err := argv.Argv([]rune(" ls `echo /` | wc -l "), os.Environ(), argv.Run)
|
args, err := argv.Argv([]rune(" ls `echo /` | wc -l "), argv.ParseEnv(os.Environ()), argv.Run)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ func TestArgv(t *testing.T) {
|
|||||||
[]string{"ls", "/"},
|
[]string{"ls", "/"},
|
||||||
[]string{"wc", "-l"},
|
[]string{"wc", "-l"},
|
||||||
}
|
}
|
||||||
if !reflect.DeepDqual(args, expects) {
|
if !reflect.DeepEqual(args, expects) {
|
||||||
t.Fatal(args)
|
t.Fatal(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
vendor/github.com/cosiner/argv/argv.go
generated
vendored
28
vendor/github.com/cosiner/argv/argv.go
generated
vendored
@ -1,34 +1,10 @@
|
|||||||
// Package argv parse command line string into arguments array using the bash syntax.
|
// Package argv parse command line string into arguments array using the bash syntax.
|
||||||
package argv
|
package argv
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// ParseEnv parsing environment variables as key/value pair.
|
|
||||||
//
|
|
||||||
// Item will be ignored if one of the key and value is empty.
|
|
||||||
func ParseEnv(env []string) map[string]string {
|
|
||||||
var m map[string]string
|
|
||||||
for _, e := range env {
|
|
||||||
secs := strings.SplitN(e, "=", 2)
|
|
||||||
if len(secs) == 2 {
|
|
||||||
key := strings.TrimSpace(secs[0])
|
|
||||||
val := strings.TrimSpace(secs[1])
|
|
||||||
if key == "" || val == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if m == nil {
|
|
||||||
m = make(map[string]string)
|
|
||||||
}
|
|
||||||
m[key] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// Argv split cmdline string as array of argument array by the '|' character.
|
// Argv split cmdline string as array of argument array by the '|' character.
|
||||||
//
|
//
|
||||||
// The parsing rules is same as bash. The environment variable will be replaced
|
// The parsing rules is same as bash. The environment variable will be replaced
|
||||||
// and string surround by '`' will be passed to reverse quote parser.
|
// and string surround by '`' will be passed to reverse quote parser.
|
||||||
func Argv(cmdline []rune, env map[string]string, reverseQuoteParser ReverseQuoteParser) ([][]string, error) {
|
func Argv(cmdline string, backquoteExpander, stringExpander Expander) ([][]string, error) {
|
||||||
return NewParser(NewScanner(cmdline, env), reverseQuoteParser).Parse()
|
return NewParser(NewScanner(cmdline), backquoteExpander, stringExpander).Parse()
|
||||||
}
|
}
|
||||||
|
60
vendor/github.com/cosiner/argv/cmd.go
generated
vendored
60
vendor/github.com/cosiner/argv/cmd.go
generated
vendored
@ -1,33 +1,13 @@
|
|||||||
package argv
|
package argv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Run execute cmdline string and return the output
|
func Cmds(args ...[]string) ([]*exec.Cmd, error) {
|
||||||
func Run(cmdline []rune, env map[string]string) ([]rune, error) {
|
|
||||||
args, err := Argv(cmdline, env, Run)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cmds, err := Cmds(args)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
output := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
||||||
err = Pipe(nil, output, cmds...)
|
|
||||||
str := output.String()
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
return []rune(str), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cmds generate exec.Cmd for each command.
|
|
||||||
func Cmds(args [][]string) ([]*exec.Cmd, error) {
|
|
||||||
var cmds []*exec.Cmd
|
var cmds []*exec.Cmd
|
||||||
for _, argv := range args {
|
for _, argv := range args {
|
||||||
if len(argv) == 0 {
|
if len(argv) == 0 {
|
||||||
@ -39,30 +19,38 @@ func Cmds(args [][]string) ([]*exec.Cmd, error) {
|
|||||||
return cmds, nil
|
return cmds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pipe pipe previous command's stdout to next command's stdin, if in or
|
func Pipe(stdin io.Reader, stdout, stderr io.Writer, cmds ...*exec.Cmd) error {
|
||||||
// out is nil, it will be ignored.
|
if stdin == nil {
|
||||||
func Pipe(in io.Reader, out io.Writer, cmds ...*exec.Cmd) error {
|
stdin = os.Stdin
|
||||||
|
}
|
||||||
|
if stdout == nil {
|
||||||
|
stdout = os.Stdout
|
||||||
|
}
|
||||||
|
if stderr == nil {
|
||||||
|
stderr = os.Stderr
|
||||||
|
}
|
||||||
l := len(cmds)
|
l := len(cmds)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
for i := 1; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
cmds[i].Stdin, err = cmds[i-1].StdoutPipe()
|
if i == 0 {
|
||||||
if err != nil {
|
cmds[i].Stdin = stdin
|
||||||
break
|
} else {
|
||||||
|
cmds[i].Stdin, err = cmds[i-1].StdoutPipe()
|
||||||
|
if stderr != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmds[i].Stderr = stderr
|
||||||
|
if i == l-1 {
|
||||||
|
cmds[i].Stdout = stdout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if in != nil {
|
|
||||||
cmds[0].Stdin = in
|
|
||||||
}
|
|
||||||
if out != nil {
|
|
||||||
cmds[l-1].Stdout = out
|
|
||||||
}
|
|
||||||
for i := range cmds {
|
for i := range cmds {
|
||||||
err = cmds[i].Start()
|
err = cmds[i].Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
3
vendor/github.com/cosiner/argv/go.mod
generated
vendored
Normal file
3
vendor/github.com/cosiner/argv/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module github.com/cosiner/argv
|
||||||
|
|
||||||
|
go 1.13
|
122
vendor/github.com/cosiner/argv/parser.go
generated
vendored
122
vendor/github.com/cosiner/argv/parser.go
generated
vendored
@ -1,17 +1,20 @@
|
|||||||
package argv
|
package argv
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// ReverseQuoteParser parse strings quoted by '`' and return it's result. Commonly,
|
Expander func(string) (string, error)
|
||||||
// it should run it os command.
|
|
||||||
ReverseQuoteParser func([]rune, map[string]string) ([]rune, error)
|
|
||||||
|
|
||||||
// Parser take tokens from Scanner, and do syntax checking, and generate the splitted arguments array.
|
// Parser take tokens from Scanner, and do syntax checking, and generate the splitted arguments array.
|
||||||
Parser struct {
|
Parser struct {
|
||||||
s *Scanner
|
s *Scanner
|
||||||
tokbuf []Token
|
tokbuf []Token
|
||||||
r ReverseQuoteParser
|
backQuoteExpander Expander
|
||||||
|
stringExpander Expander
|
||||||
|
|
||||||
sections [][]string
|
sections [][]string
|
||||||
currSection []string
|
currSection []string
|
||||||
@ -22,16 +25,23 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewParser create a cmdline string parser.
|
// NewParser create a cmdline string parser.
|
||||||
func NewParser(s *Scanner, r ReverseQuoteParser) *Parser {
|
func NewParser(s *Scanner, backQuoteExpander, stringExpander Expander) *Parser {
|
||||||
if r == nil {
|
if backQuoteExpander == nil {
|
||||||
r = func(r []rune, env map[string]string) ([]rune, error) {
|
backQuoteExpander = func(r string) (string, error) {
|
||||||
return r, nil
|
return r, fmt.Errorf("back quote doesn't allowed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if stringExpander == nil {
|
||||||
|
stringExpander = func(runes string) (string, error) {
|
||||||
|
s := os.ExpandEnv(string(runes))
|
||||||
|
return s, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Parser{
|
return &Parser{
|
||||||
s: s,
|
s: s,
|
||||||
r: r,
|
backQuoteExpander: backQuoteExpander,
|
||||||
|
stringExpander: stringExpander,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +71,7 @@ func (p *Parser) unreadToken(tok Token) {
|
|||||||
// Section = [Space] SpacedSection { SpacedSection }
|
// Section = [Space] SpacedSection { SpacedSection }
|
||||||
// SpacedSection = MultipleUnit [Space]
|
// SpacedSection = MultipleUnit [Space]
|
||||||
// MultipleUnit = Unit {Unit}
|
// MultipleUnit = Unit {Unit}
|
||||||
// Unit = String | ReverseQuote
|
// Unit = String | BackQuote | SingleQuote | DoubleQuote
|
||||||
func (p *Parser) Parse() ([][]string, error) {
|
func (p *Parser) Parse() ([][]string, error) {
|
||||||
err := p.cmdline()
|
err := p.cmdline()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -96,23 +106,26 @@ func (p *Parser) section() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var isFirst = true
|
var hasUnit bool
|
||||||
for {
|
for {
|
||||||
unit, err := p.spacedSection()
|
unit, ok, err := p.spacedSection()
|
||||||
if isFirst {
|
|
||||||
isFirst = false
|
|
||||||
} else {
|
|
||||||
if err == ErrInvalidSyntax {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
hasUnit = true
|
||||||
|
|
||||||
p.appendUnit(leftSpace, unit)
|
err = p.appendUnit(leftSpace, unit)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
leftSpace = unit.rightSpace
|
leftSpace = unit.rightSpace
|
||||||
}
|
}
|
||||||
|
if !hasUnit {
|
||||||
|
return ErrInvalidSyntax
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,47 +134,45 @@ type unit struct {
|
|||||||
toks []Token
|
toks []Token
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) spacedSection() (u unit, err error) {
|
func (p *Parser) spacedSection() (u unit, ok bool, err error) {
|
||||||
u.toks, err = p.multipleUnit()
|
u.toks, ok, err = p.multipleUnit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !ok {
|
||||||
|
return u, false, nil
|
||||||
|
}
|
||||||
u.rightSpace, err = p.optional(TokSpace)
|
u.rightSpace, err = p.optional(TokSpace)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) multipleUnit() ([]Token, error) {
|
func (p *Parser) multipleUnit() ([]Token, bool, error) {
|
||||||
var (
|
var (
|
||||||
toks []Token
|
toks []Token
|
||||||
isFirst = true
|
|
||||||
)
|
)
|
||||||
for {
|
for {
|
||||||
tok, err := p.unit()
|
tok, ok, err := p.unit()
|
||||||
if isFirst {
|
|
||||||
isFirst = false
|
|
||||||
} else {
|
|
||||||
if err == ErrInvalidSyntax {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, false, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
toks = append(toks, tok)
|
toks = append(toks, tok)
|
||||||
}
|
}
|
||||||
return toks, nil
|
return toks, len(toks) > 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) unit() (Token, error) {
|
func (p *Parser) unit() (Token, bool, error) {
|
||||||
tok, err := p.nextToken()
|
tok, err := p.nextToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tok, err
|
return tok, false, err
|
||||||
}
|
}
|
||||||
if p.accept(tok.Type, TokString, TokReversequote) {
|
if p.accept(tok.Type, TokString, TokStringSingleQuote, TokStringDoubleQuote, TokBackQuote) {
|
||||||
return tok, nil
|
return tok, true, nil
|
||||||
}
|
}
|
||||||
p.unreadToken(tok)
|
p.unreadToken(tok)
|
||||||
return tok, ErrInvalidSyntax
|
return tok, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) optional(typ TokenType) (bool, error) {
|
func (p *Parser) optional(typ TokenType) (bool, error) {
|
||||||
@ -190,14 +201,27 @@ func (p *Parser) appendUnit(leftSpace bool, u unit) error {
|
|||||||
p.currStr = p.currStr[:0]
|
p.currStr = p.currStr[:0]
|
||||||
}
|
}
|
||||||
for _, tok := range u.toks {
|
for _, tok := range u.toks {
|
||||||
if tok.Type == TokReversequote {
|
switch tok.Type {
|
||||||
val, err := p.r(tok.Value, p.s.envs())
|
case TokBackQuote:
|
||||||
|
expanded, err := p.backQuoteExpander(string(tok.Value))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("expand string back quoted failed: %s, %w", string(tok.Value), err)
|
||||||
}
|
}
|
||||||
p.currStr = append(p.currStr, val...)
|
p.currStr = append(p.currStr, []rune(expanded)...)
|
||||||
} else {
|
case TokString:
|
||||||
|
expanded, err := p.stringExpander(string(tok.Value))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("expand string failed: %s, %w", string(tok.Value), err)
|
||||||
|
}
|
||||||
|
p.currStr = append(p.currStr, []rune(expanded)...)
|
||||||
|
case TokStringSingleQuote:
|
||||||
p.currStr = append(p.currStr, tok.Value...)
|
p.currStr = append(p.currStr, tok.Value...)
|
||||||
|
case TokStringDoubleQuote:
|
||||||
|
expanded, err := p.stringExpander(string(tok.Value))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("expand string double quoted failed: %s, %w", string(tok.Value), err)
|
||||||
|
}
|
||||||
|
p.currStr = append(p.currStr, []rune(expanded)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.currStrValid = true
|
p.currStrValid = true
|
||||||
|
150
vendor/github.com/cosiner/argv/scanner.go
generated
vendored
150
vendor/github.com/cosiner/argv/scanner.go
generated
vendored
@ -1,30 +1,24 @@
|
|||||||
package argv
|
package argv
|
||||||
|
|
||||||
import "unicode"
|
import (
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
// Scanner is a cmdline string scanner.
|
// Scanner is a cmdline string scanner.
|
||||||
//
|
//
|
||||||
// It split cmdline string to tokens: space, string, pipe, reverse quote string.
|
// It split cmdline string to tokens: space, string, pipe, reverse quote string.
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
env map[string]string
|
text []rune
|
||||||
|
rpos int
|
||||||
text []rune
|
|
||||||
rpos int
|
|
||||||
dollarBuf []rune
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScanner create a scanner and init it's internal states.
|
// NewScanner create a scanner and init it's internal states.
|
||||||
func NewScanner(text []rune, env map[string]string) *Scanner {
|
func NewScanner(text string) *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
text: text,
|
text: []rune(text),
|
||||||
env: env,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scanner) envs() map[string]string {
|
|
||||||
return s.env
|
|
||||||
}
|
|
||||||
|
|
||||||
const _RuneEOF = 0
|
const _RuneEOF = 0
|
||||||
|
|
||||||
func (s *Scanner) nextRune() rune {
|
func (s *Scanner) nextRune() rune {
|
||||||
@ -67,13 +61,6 @@ func (s *Scanner) isEscapeChars(r rune) (rune, bool) {
|
|||||||
return r, false
|
return r, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scanner) endEnv(r rune) bool {
|
|
||||||
if r == '_' || (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenType is the type of tokens recognized by the scanner.
|
// TokenType is the type of tokens recognized by the scanner.
|
||||||
type TokenType uint32
|
type TokenType uint32
|
||||||
|
|
||||||
@ -84,61 +71,20 @@ type Token struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TokString for string, single quoted string and double quoted string
|
// TokString for string
|
||||||
TokString TokenType = iota + 1
|
TokString TokenType = iota + 1
|
||||||
|
TokStringSingleQuote
|
||||||
|
TokStringDoubleQuote
|
||||||
// TokPipe is the '|' character
|
// TokPipe is the '|' character
|
||||||
TokPipe
|
TokPipe
|
||||||
// TokReversequote is reverse quoted string
|
// TokBackQuote is reverse quoted string
|
||||||
TokReversequote
|
TokBackQuote
|
||||||
// TokSpace represent space character sequence
|
// TokSpace represent space character sequence
|
||||||
TokSpace
|
TokSpace
|
||||||
// TokEOF means the input end.
|
// TokEOF means the input end.
|
||||||
TokEOF
|
TokEOF
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Scanner) getEnv(name string) string {
|
|
||||||
return s.env[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Scanner) specialVar(r rune) (string, bool) {
|
|
||||||
switch r {
|
|
||||||
case '0', '*', '#', '@', '?', '$':
|
|
||||||
v, has := s.env[string(r)]
|
|
||||||
return v, has
|
|
||||||
default:
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Scanner) checkDollarStart(tok *Token, r rune, from, switchTo uint8) uint8 {
|
|
||||||
state := from
|
|
||||||
nr := s.nextRune()
|
|
||||||
if val, has := s.specialVar(nr); has {
|
|
||||||
if val != "" {
|
|
||||||
tok.Value = append(tok.Value, []rune(val)...)
|
|
||||||
}
|
|
||||||
} else if s.endEnv(nr) {
|
|
||||||
tok.Value = append(tok.Value, r)
|
|
||||||
s.unreadRune(nr)
|
|
||||||
} else {
|
|
||||||
state = switchTo
|
|
||||||
s.dollarBuf = append(s.dollarBuf[:0], nr)
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Scanner) checkDollarEnd(tok *Token, r rune, from, switchTo uint8) uint8 {
|
|
||||||
var state = from
|
|
||||||
if s.endEnv(r) {
|
|
||||||
tok.Value = append(tok.Value, []rune(s.getEnv(string(s.dollarBuf)))...)
|
|
||||||
state = switchTo
|
|
||||||
s.unreadRune(r)
|
|
||||||
} else {
|
|
||||||
s.dollarBuf = append(s.dollarBuf, r)
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next return next token, if it reach the end, TOK_EOF will be returned.
|
// Next return next token, if it reach the end, TOK_EOF will be returned.
|
||||||
//
|
//
|
||||||
// Error is returned for invalid syntax such as unpaired quotes.
|
// Error is returned for invalid syntax such as unpaired quotes.
|
||||||
@ -146,12 +92,10 @@ func (s *Scanner) Next() (Token, error) {
|
|||||||
const (
|
const (
|
||||||
Initial = iota + 1
|
Initial = iota + 1
|
||||||
Space
|
Space
|
||||||
ReverseQuote
|
BackQuote
|
||||||
String
|
String
|
||||||
StringDollar
|
StringSingleQuote
|
||||||
StringQuoteSingle
|
StringDoubleQuote
|
||||||
StringQuoteDouble
|
|
||||||
StringQuoteDoubleDollar
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -159,7 +103,6 @@ func (s *Scanner) Next() (Token, error) {
|
|||||||
|
|
||||||
state uint8 = Initial
|
state uint8 = Initial
|
||||||
)
|
)
|
||||||
s.dollarBuf = s.dollarBuf[:0]
|
|
||||||
for {
|
for {
|
||||||
r := s.nextRune()
|
r := s.nextRune()
|
||||||
switch state {
|
switch state {
|
||||||
@ -172,10 +115,14 @@ func (s *Scanner) Next() (Token, error) {
|
|||||||
tok.Type = TokPipe
|
tok.Type = TokPipe
|
||||||
return tok, nil
|
return tok, nil
|
||||||
case r == '`':
|
case r == '`':
|
||||||
state = ReverseQuote
|
state = BackQuote
|
||||||
case unicode.IsSpace(r):
|
case unicode.IsSpace(r):
|
||||||
state = Space
|
state = Space
|
||||||
s.unreadRune(r)
|
s.unreadRune(r)
|
||||||
|
case r == '\'':
|
||||||
|
state = StringSingleQuote
|
||||||
|
case r == '"':
|
||||||
|
state = StringDoubleQuote
|
||||||
default:
|
default:
|
||||||
state = String
|
state = String
|
||||||
s.unreadRune(r)
|
s.unreadRune(r)
|
||||||
@ -186,45 +133,46 @@ func (s *Scanner) Next() (Token, error) {
|
|||||||
tok.Type = TokSpace
|
tok.Type = TokSpace
|
||||||
return tok, nil
|
return tok, nil
|
||||||
}
|
}
|
||||||
case ReverseQuote:
|
case BackQuote:
|
||||||
switch r {
|
switch r {
|
||||||
case _RuneEOF:
|
case _RuneEOF:
|
||||||
return tok, ErrInvalidSyntax
|
return tok, ErrInvalidSyntax
|
||||||
case '`':
|
case '`':
|
||||||
tok.Type = TokReversequote
|
tok.Type = TokBackQuote
|
||||||
return tok, nil
|
return tok, nil
|
||||||
default:
|
default:
|
||||||
tok.Value = append(tok.Value, r)
|
tok.Value = append(tok.Value, r)
|
||||||
}
|
}
|
||||||
case String:
|
case String:
|
||||||
switch {
|
switch {
|
||||||
case r == _RuneEOF || r == '|' || r == '`' || unicode.IsSpace(r):
|
case r == _RuneEOF, r == '|', r == '`', r == '\'', r == '"', unicode.IsSpace(r):
|
||||||
tok.Type = TokString
|
tok.Type = TokString
|
||||||
s.unreadRune(r)
|
s.unreadRune(r)
|
||||||
return tok, nil
|
return tok, nil
|
||||||
case r == '\'':
|
|
||||||
state = StringQuoteSingle
|
|
||||||
case r == '"':
|
|
||||||
state = StringQuoteDouble
|
|
||||||
case r == '\\':
|
case r == '\\':
|
||||||
nr := s.nextRune()
|
nr := s.nextRune()
|
||||||
if nr == _RuneEOF {
|
if nr == _RuneEOF {
|
||||||
return tok, ErrInvalidSyntax
|
return tok, ErrInvalidSyntax
|
||||||
}
|
}
|
||||||
tok.Value = append(tok.Value, nr)
|
tok.Value = append(tok.Value, nr)
|
||||||
case r == '$':
|
|
||||||
state = s.checkDollarStart(&tok, r, state, StringDollar)
|
|
||||||
default:
|
default:
|
||||||
tok.Value = append(tok.Value, r)
|
tok.Value = append(tok.Value, r)
|
||||||
}
|
}
|
||||||
case StringDollar:
|
case StringSingleQuote, StringDoubleQuote:
|
||||||
state = s.checkDollarEnd(&tok, r, state, String)
|
|
||||||
case StringQuoteSingle:
|
|
||||||
switch r {
|
switch r {
|
||||||
case _RuneEOF:
|
case _RuneEOF:
|
||||||
return tok, ErrInvalidSyntax
|
return tok, ErrInvalidSyntax
|
||||||
case '\'':
|
case '\'', '"':
|
||||||
state = String
|
if singleQuote := state == StringSingleQuote; singleQuote == (r == '\'') {
|
||||||
|
if singleQuote {
|
||||||
|
tok.Type = TokStringSingleQuote
|
||||||
|
} else {
|
||||||
|
tok.Type = TokStringDoubleQuote
|
||||||
|
}
|
||||||
|
return tok, nil
|
||||||
|
} else {
|
||||||
|
tok.Value = append(tok.Value, r)
|
||||||
|
}
|
||||||
case '\\':
|
case '\\':
|
||||||
nr := s.nextRune()
|
nr := s.nextRune()
|
||||||
if escape, ok := s.isEscapeChars(nr); ok {
|
if escape, ok := s.isEscapeChars(nr); ok {
|
||||||
@ -236,37 +184,13 @@ func (s *Scanner) Next() (Token, error) {
|
|||||||
default:
|
default:
|
||||||
tok.Value = append(tok.Value, r)
|
tok.Value = append(tok.Value, r)
|
||||||
}
|
}
|
||||||
case StringQuoteDouble:
|
|
||||||
switch r {
|
|
||||||
case _RuneEOF:
|
|
||||||
return tok, ErrInvalidSyntax
|
|
||||||
case '"':
|
|
||||||
state = String
|
|
||||||
case '\\':
|
|
||||||
nr := s.nextRune()
|
|
||||||
if nr == _RuneEOF {
|
|
||||||
return tok, ErrInvalidSyntax
|
|
||||||
}
|
|
||||||
if escape, ok := s.isEscapeChars(nr); ok {
|
|
||||||
tok.Value = append(tok.Value, escape)
|
|
||||||
} else {
|
|
||||||
tok.Value = append(tok.Value, r)
|
|
||||||
s.unreadRune(nr)
|
|
||||||
}
|
|
||||||
case '$':
|
|
||||||
state = s.checkDollarStart(&tok, r, state, StringQuoteDoubleDollar)
|
|
||||||
default:
|
|
||||||
tok.Value = append(tok.Value, r)
|
|
||||||
}
|
|
||||||
case StringQuoteDoubleDollar:
|
|
||||||
state = s.checkDollarEnd(&tok, r, state, StringQuoteDouble)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan is a utility function help split input text as tokens.
|
// Scan is a utility function help split input text as tokens.
|
||||||
func Scan(text []rune, env map[string]string) ([]Token, error) {
|
func Scan(text string) ([]Token, error) {
|
||||||
s := NewScanner(text, env)
|
s := NewScanner(text)
|
||||||
var tokens []Token
|
var tokens []Token
|
||||||
for {
|
for {
|
||||||
tok, err := s.Next()
|
tok, err := s.Next()
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -1,4 +1,4 @@
|
|||||||
# github.com/cosiner/argv v0.0.0-20170225145430-13bacc38a0a5
|
# github.com/cosiner/argv v0.1.0
|
||||||
github.com/cosiner/argv
|
github.com/cosiner/argv
|
||||||
# github.com/cpuguy83/go-md2man v1.0.10
|
# github.com/cpuguy83/go-md2man v1.0.10
|
||||||
github.com/cpuguy83/go-md2man/md2man
|
github.com/cpuguy83/go-md2man/md2man
|
||||||
|
Loading…
Reference in New Issue
Block a user