2022-11-17 07:17:38 +01:00
|
|
|
package shparse
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"unicode"
|
|
|
|
"unicode/utf8"
|
|
|
|
|
|
|
|
"github.com/scripthaus-dev/sh2-server/pkg/utilfn"
|
|
|
|
)
|
|
|
|
|
|
|
|
var noEscChars []bool
|
|
|
|
var specialEsc []string
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
noEscChars = make([]bool, 256)
|
|
|
|
for ch := 0; ch < 256; ch++ {
|
|
|
|
if (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
|
|
|
|
ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '=' {
|
|
|
|
noEscChars[byte(ch)] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
specialEsc = make([]string, 256)
|
|
|
|
specialEsc[0x7] = "\\a"
|
|
|
|
specialEsc[0x8] = "\\b"
|
|
|
|
specialEsc[0x9] = "\\t"
|
|
|
|
specialEsc[0xa] = "\\n"
|
|
|
|
specialEsc[0xb] = "\\v"
|
|
|
|
specialEsc[0xc] = "\\f"
|
|
|
|
specialEsc[0xd] = "\\r"
|
|
|
|
specialEsc[0x1b] = "\\E"
|
|
|
|
}
|
|
|
|
|
|
|
|
func getUtf8Literal(ch rune) string {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
var runeArr [utf8.UTFMax]byte
|
|
|
|
barr := runeArr[:]
|
|
|
|
byteLen := utf8.EncodeRune(barr, ch)
|
|
|
|
for i := 0; i < byteLen; i++ {
|
|
|
|
buf.WriteString("\\x")
|
|
|
|
buf.WriteByte(utilfn.HexDigits[barr[i]/16])
|
|
|
|
buf.WriteByte(utilfn.HexDigits[barr[i]%16])
|
|
|
|
}
|
|
|
|
return buf.String()
|
|
|
|
}
|
|
|
|
|
2022-11-18 09:09:18 +01:00
|
|
|
func (w *WordType) writeString(s string) {
|
2022-11-17 07:17:38 +01:00
|
|
|
for _, ch := range s {
|
|
|
|
w.writeRune(ch)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-18 09:09:18 +01:00
|
|
|
func (w *WordType) writeRune(ch rune) {
|
2022-11-17 08:52:10 +01:00
|
|
|
wmeta := wordMetaMap[w.Type]
|
|
|
|
if w.Complete && wmeta.SuffixLen == 1 {
|
|
|
|
w.Raw = append(w.Raw[0:len(w.Raw)-1], ch, w.Raw[len(w.Raw)-1])
|
2022-11-17 07:17:38 +01:00
|
|
|
return
|
|
|
|
}
|
2022-11-17 08:52:10 +01:00
|
|
|
if w.Complete && wmeta.SuffixLen == 2 {
|
|
|
|
w.Raw = append(w.Raw[0:len(w.Raw)-2], ch, w.Raw[len(w.Raw)-2], w.Raw[len(w.Raw)-1])
|
2022-11-17 07:17:38 +01:00
|
|
|
return
|
|
|
|
}
|
2022-11-17 08:52:10 +01:00
|
|
|
// not complete or SuffixLen == 0 (2+ is not supported)
|
|
|
|
w.Raw = append(w.Raw, ch)
|
|
|
|
return
|
2022-11-17 07:17:38 +01:00
|
|
|
}
|
|
|
|
|
2022-11-18 09:09:18 +01:00
|
|
|
func (w *WordType) cloneRaw() {
|
2022-11-17 07:17:38 +01:00
|
|
|
if len(w.Raw) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
buf := make([]rune, 0, len(w.Raw))
|
|
|
|
w.Raw = append(buf, w.Raw...)
|
|
|
|
}
|
|
|
|
|
|
|
|
type extendContext struct {
|
2022-11-18 09:09:18 +01:00
|
|
|
QC QuoteContext
|
|
|
|
Rtn []*WordType
|
|
|
|
CurWord *WordType
|
2022-11-17 07:17:38 +01:00
|
|
|
Intention string
|
|
|
|
}
|
|
|
|
|
2022-11-18 09:09:18 +01:00
|
|
|
func makeExtendContext(qc QuoteContext, w *WordType) *extendContext {
|
2022-11-17 08:52:10 +01:00
|
|
|
rtn := &extendContext{QC: qc, Intention: WordTypeLit}
|
2022-11-17 07:17:38 +01:00
|
|
|
if w != nil {
|
|
|
|
w.cloneRaw()
|
2022-11-18 09:09:18 +01:00
|
|
|
rtn.Rtn = []*WordType{w}
|
2022-11-17 07:17:38 +01:00
|
|
|
rtn.CurWord = w
|
2022-11-17 08:52:10 +01:00
|
|
|
rtn.Intention = w.Type
|
2022-11-17 07:17:38 +01:00
|
|
|
}
|
|
|
|
return rtn
|
|
|
|
}
|
|
|
|
|
2022-11-18 09:09:18 +01:00
|
|
|
func (ec *extendContext) appendWord(w *WordType) {
|
2022-11-17 07:17:38 +01:00
|
|
|
ec.Rtn = append(ec.Rtn, w)
|
|
|
|
ec.CurWord = w
|
|
|
|
}
|
|
|
|
|
2022-11-17 08:52:10 +01:00
|
|
|
func (ec *extendContext) ensureCurWord() {
|
|
|
|
if ec.CurWord == nil || ec.CurWord.Type != ec.Intention {
|
2022-11-18 09:09:18 +01:00
|
|
|
ec.CurWord = MakeEmptyWord(ec.Intention, ec.QC, 0)
|
2022-11-17 08:52:10 +01:00
|
|
|
ec.Rtn = append(ec.Rtn, ec.CurWord)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-17 07:17:38 +01:00
|
|
|
func (ec *extendContext) extend(ch rune) {
|
|
|
|
if ch == 0 {
|
|
|
|
return
|
|
|
|
}
|
2022-11-17 08:52:10 +01:00
|
|
|
switch ec.Intention {
|
2022-11-17 07:17:38 +01:00
|
|
|
|
2022-11-17 08:52:10 +01:00
|
|
|
case WordTypeSimpleVar, WordTypeVarBrace:
|
|
|
|
ec.extendVar(ch)
|
2022-11-17 07:17:38 +01:00
|
|
|
|
2022-11-17 08:52:10 +01:00
|
|
|
case WordTypeDQ, WordTypeDDQ:
|
|
|
|
ec.extendDQ(ch)
|
2022-11-17 07:17:38 +01:00
|
|
|
|
|
|
|
case WordTypeSQ:
|
|
|
|
ec.extendSQ(ch)
|
|
|
|
|
|
|
|
case WordTypeDSQ:
|
2022-11-17 08:52:10 +01:00
|
|
|
ec.extendDSQ(ch)
|
2022-11-17 07:17:38 +01:00
|
|
|
|
|
|
|
case WordTypeLit:
|
2022-11-17 08:52:10 +01:00
|
|
|
ec.extendLit(ch)
|
2022-11-17 07:17:38 +01:00
|
|
|
|
|
|
|
default:
|
2022-11-17 08:52:10 +01:00
|
|
|
return
|
2022-11-17 07:17:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSpecialEscape(ch rune) string {
|
|
|
|
if ch > unicode.MaxASCII {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return specialEsc[byte(ch)]
|
|
|
|
}
|
|
|
|
|
2022-11-17 08:52:10 +01:00
|
|
|
func isVarNameChar(ch rune) bool {
|
|
|
|
return ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *extendContext) extendVar(ch rune) {
|
|
|
|
if ch == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !isVarNameChar(ch) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ec.ensureCurWord()
|
|
|
|
ec.CurWord.writeRune(ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *extendContext) extendLit(ch rune) {
|
|
|
|
if ch == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if ch > unicode.MaxASCII || !unicode.IsPrint(ch) {
|
2022-11-18 09:09:18 +01:00
|
|
|
dsqWord := MakeEmptyWord(WordTypeDSQ, ec.QC, 0)
|
2022-11-17 08:52:10 +01:00
|
|
|
ec.appendWord(dsqWord)
|
|
|
|
sesc := getSpecialEscape(ch)
|
|
|
|
if sesc != "" {
|
|
|
|
dsqWord.writeString(sesc)
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
utf8Lit := getUtf8Literal(ch)
|
|
|
|
dsqWord.writeString(utf8Lit)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var bch = byte(ch)
|
|
|
|
ec.ensureCurWord()
|
|
|
|
if noEscChars[bch] {
|
|
|
|
ec.CurWord.writeRune(ch)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ec.CurWord.writeRune('\\')
|
|
|
|
ec.CurWord.writeRune(ch)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *extendContext) extendDSQ(ch rune) {
|
|
|
|
if ch == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ec.ensureCurWord()
|
|
|
|
if ch == '\'' {
|
|
|
|
ec.CurWord.writeRune('\\')
|
|
|
|
ec.CurWord.writeRune(ch)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if ch > unicode.MaxASCII || !unicode.IsPrint(ch) {
|
|
|
|
sesc := getSpecialEscape(ch)
|
|
|
|
if sesc != "" {
|
|
|
|
ec.CurWord.writeString(sesc)
|
|
|
|
} else {
|
|
|
|
utf8Lit := getUtf8Literal(ch)
|
|
|
|
ec.CurWord.writeString(utf8Lit)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ec.CurWord.writeRune(ch)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-11-17 07:17:38 +01:00
|
|
|
func (ec *extendContext) extendSQ(ch rune) {
|
|
|
|
if ch == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if ch == '\'' {
|
2022-11-18 09:09:18 +01:00
|
|
|
litWord := &WordType{Type: WordTypeLit, QC: ec.QC}
|
2022-11-17 07:17:38 +01:00
|
|
|
litWord.Raw = []rune{'\\', '\''}
|
|
|
|
ec.appendWord(litWord)
|
2022-11-17 08:52:10 +01:00
|
|
|
return
|
2022-11-17 07:17:38 +01:00
|
|
|
}
|
|
|
|
if ch > unicode.MaxASCII || !unicode.IsPrint(ch) {
|
2022-11-18 09:09:18 +01:00
|
|
|
dsqWord := MakeEmptyWord(WordTypeDSQ, ec.QC, 0)
|
2022-11-17 07:17:38 +01:00
|
|
|
ec.appendWord(dsqWord)
|
|
|
|
sesc := getSpecialEscape(ch)
|
|
|
|
if sesc != "" {
|
|
|
|
dsqWord.writeString(sesc)
|
|
|
|
} else {
|
|
|
|
utf8Lit := getUtf8Literal(ch)
|
|
|
|
dsqWord.writeString(utf8Lit)
|
|
|
|
}
|
2022-11-17 08:52:10 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
ec.ensureCurWord()
|
|
|
|
ec.CurWord.writeRune(ch)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *extendContext) extendDQ(ch rune) {
|
|
|
|
if ch == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if ch == '"' || ch == '\\' || ch == '$' || ch == '`' {
|
|
|
|
ec.ensureCurWord()
|
|
|
|
ec.CurWord.writeRune('\\')
|
|
|
|
ec.CurWord.writeRune(ch)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if ch > unicode.MaxASCII || !unicode.IsPrint(ch) {
|
2022-11-18 09:09:18 +01:00
|
|
|
dsqWord := MakeEmptyWord(WordTypeDSQ, ec.QC, 0)
|
2022-11-17 08:52:10 +01:00
|
|
|
ec.appendWord(dsqWord)
|
|
|
|
sesc := getSpecialEscape(ch)
|
|
|
|
if sesc != "" {
|
|
|
|
dsqWord.writeString(sesc)
|
|
|
|
} else {
|
|
|
|
utf8Lit := getUtf8Literal(ch)
|
|
|
|
dsqWord.writeString(utf8Lit)
|
|
|
|
}
|
|
|
|
return
|
2022-11-17 07:17:38 +01:00
|
|
|
}
|
|
|
|
ec.CurWord.writeRune(ch)
|
2022-11-17 08:52:10 +01:00
|
|
|
return
|
2022-11-17 07:17:38 +01:00
|
|
|
}
|