Version 0.0.1
This commit is contained in:
parent
a7853c1177
commit
1be805317f
107
quotearg.go
107
quotearg.go
@ -5,6 +5,11 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
lowerHex = []rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}
|
||||||
|
upperHex = []rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
QAElideNullBytes = 0x01
|
QAElideNullBytes = 0x01
|
||||||
QAElideOuterQuotes = 0x02
|
QAElideOuterQuotes = 0x02
|
||||||
@ -59,7 +64,7 @@ func GetTextQuote(s QuotingStyle) rune {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func QuoteargBufferRestyled(
|
func Quote(
|
||||||
buffer []rune,
|
buffer []rune,
|
||||||
arg []rune,
|
arg []rune,
|
||||||
style QuotingStyle,
|
style QuotingStyle,
|
||||||
@ -67,24 +72,18 @@ func QuoteargBufferRestyled(
|
|||||||
quoteTheseToo uint,
|
quoteTheseToo uint,
|
||||||
leftQuote rune,
|
leftQuote rune,
|
||||||
rightQuote rune,
|
rightQuote rune,
|
||||||
) {
|
) []rune {
|
||||||
var pos int
|
|
||||||
var elideOuterQuotes bool = (flags & QAElideOuterQuotes) != 0
|
var elideOuterQuotes bool = (flags & QAElideOuterQuotes) != 0
|
||||||
var pendingShellEscapeEnd bool
|
var pendingShellEscapeEnd bool
|
||||||
var escaping bool
|
var escaping bool
|
||||||
var quoteRune rune
|
var quoteRune rune
|
||||||
var backslashEscapes bool
|
var backslashEscapes bool
|
||||||
var allCAndShellQuoteCompat bool = true
|
|
||||||
|
|
||||||
store := func(c rune) {
|
store := func(c rune) {
|
||||||
buffer[pos] = c
|
buffer = append(buffer, c)
|
||||||
pos++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startESC := func() {
|
startESC := func() {
|
||||||
if elideOuterQuotes {
|
|
||||||
goto ForceOuterQuotingStyle
|
|
||||||
}
|
|
||||||
escaping = true
|
escaping = true
|
||||||
if style == ShellAlwaysQuotingStyle && !pendingShellEscapeEnd {
|
if style == ShellAlwaysQuotingStyle && !pendingShellEscapeEnd {
|
||||||
store('\'')
|
store('\'')
|
||||||
@ -159,9 +158,9 @@ func QuoteargBufferRestyled(
|
|||||||
for i := 0; i < len(arg); i++ {
|
for i := 0; i < len(arg); i++ {
|
||||||
var esc rune
|
var esc rune
|
||||||
var isRightQuote bool
|
var isRightQuote bool
|
||||||
var cAndShellQuoteCompat bool
|
escaping = false
|
||||||
|
|
||||||
quoteIsNext := arg[i+1] == quoteRune
|
quoteIsNext := len(arg) > i+1 && arg[i+1] == quoteRune
|
||||||
|
|
||||||
if backslashEscapes &&
|
if backslashEscapes &&
|
||||||
style != ShellAlwaysQuotingStyle &&
|
style != ShellAlwaysQuotingStyle &&
|
||||||
@ -177,6 +176,9 @@ func QuoteargBufferRestyled(
|
|||||||
switch c {
|
switch c {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
if backslashEscapes {
|
if backslashEscapes {
|
||||||
|
if elideOuterQuotes {
|
||||||
|
goto ForceOuterQuotingStyle
|
||||||
|
}
|
||||||
startESC()
|
startESC()
|
||||||
if style != ShellQuotingStyle &&
|
if style != ShellQuotingStyle &&
|
||||||
i+1 < len(arg) &&
|
i+1 < len(arg) &&
|
||||||
@ -189,7 +191,7 @@ func QuoteargBufferRestyled(
|
|||||||
} else if flags&QAElideNullBytes != 0 {
|
} else if flags&QAElideNullBytes != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
break
|
goto StoreEscape
|
||||||
case '?':
|
case '?':
|
||||||
switch style {
|
switch style {
|
||||||
case ShellAlwaysQuotingStyle:
|
case ShellAlwaysQuotingStyle:
|
||||||
@ -222,7 +224,7 @@ func QuoteargBufferRestyled(
|
|||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
break
|
goto StoreEscape
|
||||||
case '\a':
|
case '\a':
|
||||||
esc = 'a'
|
esc = 'a'
|
||||||
goto CEscape
|
goto CEscape
|
||||||
@ -257,30 +259,19 @@ func QuoteargBufferRestyled(
|
|||||||
goto StoreC
|
goto StoreC
|
||||||
}
|
}
|
||||||
|
|
||||||
CAndShellEscape:
|
goto CAndShellEscape
|
||||||
if style == ShellAlwaysQuotingStyle && elideOuterQuotes {
|
|
||||||
goto ForceOuterQuotingStyle
|
|
||||||
}
|
|
||||||
|
|
||||||
CEscape:
|
|
||||||
if backslashEscapes {
|
|
||||||
c = esc
|
|
||||||
goto StoreEscape
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case '{', '}':
|
case '{', '}':
|
||||||
if len(arg) != 1 {
|
if len(arg) != 1 {
|
||||||
break
|
goto StoreEscape
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case '#', '~':
|
case '#', '~':
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
break
|
goto StoreEscape
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case ' ':
|
case ' ':
|
||||||
cAndShellQuoteCompat = true
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case '!', '"', '$', '&', '(', ')', '*', ';', '<', '=', '>', '[':
|
case '!', '"', '$', '&', '(', ')', '*', ';', '<', '=', '>', '[':
|
||||||
fallthrough
|
fallthrough
|
||||||
@ -288,10 +279,8 @@ func QuoteargBufferRestyled(
|
|||||||
if style == ShellAlwaysQuotingStyle && elideOuterQuotes {
|
if style == ShellAlwaysQuotingStyle && elideOuterQuotes {
|
||||||
goto ForceOuterQuotingStyle
|
goto ForceOuterQuotingStyle
|
||||||
}
|
}
|
||||||
break
|
goto StoreEscape
|
||||||
case '\'':
|
case '\'':
|
||||||
encounteredSingleQuote = true
|
|
||||||
cAndShellQuoteCompat = true
|
|
||||||
if style == ShellAlwaysQuotingStyle {
|
if style == ShellAlwaysQuotingStyle {
|
||||||
if elideOuterQuotes {
|
if elideOuterQuotes {
|
||||||
goto ForceOuterQuotingStyle
|
goto ForceOuterQuotingStyle
|
||||||
@ -303,7 +292,7 @@ func QuoteargBufferRestyled(
|
|||||||
store('\'')
|
store('\'')
|
||||||
pendingShellEscapeEnd = false
|
pendingShellEscapeEnd = false
|
||||||
}
|
}
|
||||||
break
|
goto StoreC
|
||||||
case '%', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5':
|
case '%', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5':
|
||||||
fallthrough
|
fallthrough
|
||||||
case '6', '7', '8', '9', ':', 'A', 'B', 'C', 'D', 'E', 'F':
|
case '6', '7', '8', '9', ':', 'A', 'B', 'C', 'D', 'E', 'F':
|
||||||
@ -315,37 +304,49 @@ func QuoteargBufferRestyled(
|
|||||||
case 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n':
|
case 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n':
|
||||||
fallthrough
|
fallthrough
|
||||||
case 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z':
|
case 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z':
|
||||||
cAndShellQuoteCompat = true
|
goto StoreC
|
||||||
break
|
|
||||||
default:
|
default:
|
||||||
printable := strconv.IsPrint(c)
|
if backslashEscapes && !strconv.IsPrint(c) {
|
||||||
cAndShellQuoteCompat = printable
|
if elideOuterQuotes {
|
||||||
if backslashEscapes && !printable {
|
goto ForceOuterQuotingStyle
|
||||||
startESC()
|
}
|
||||||
store('x')
|
|
||||||
switch {
|
switch {
|
||||||
case c < ' ':
|
case c < ' ':
|
||||||
store(byte(c) >> 4)
|
startESC()
|
||||||
store(byte(c) & 0xF)
|
store('x')
|
||||||
|
store(upperHex[byte(c)>>4])
|
||||||
|
store(upperHex[byte(c)&0xF])
|
||||||
case c > utf8.MaxRune:
|
case c > utf8.MaxRune:
|
||||||
c = 0xFFFD
|
c = 0xFFFD
|
||||||
fallthrough
|
fallthrough
|
||||||
case c < 0x10000:
|
case c < 0x10000:
|
||||||
|
startESC()
|
||||||
|
store('u')
|
||||||
for s := 12; s >= 0; s -= 4 {
|
for s := 12; s >= 0; s -= 4 {
|
||||||
store(c >> uint(s) & 0xF)
|
store(upperHex[c>>uint(s)&0xF])
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
startESC()
|
||||||
|
store('U')
|
||||||
for s := 28; s >= 0; s -= 4 {
|
for s := 28; s >= 0; s -= 4 {
|
||||||
store(c >> uint(s) & 0xF)
|
store(upperHex[c>>uint(s)&0xF])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goto StoreC
|
|
||||||
} else if isRightQuote {
|
} else if isRightQuote {
|
||||||
store('\\')
|
store('\\')
|
||||||
isRightQuote = false
|
isRightQuote = false
|
||||||
}
|
}
|
||||||
goto StoreC
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
CAndShellEscape:
|
||||||
|
if style == ShellAlwaysQuotingStyle && elideOuterQuotes {
|
||||||
|
goto ForceOuterQuotingStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
CEscape:
|
||||||
|
if backslashEscapes {
|
||||||
|
c = esc
|
||||||
|
goto StoreEscape
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(((backslashEscapes && style != ShellAlwaysQuotingStyle) ||
|
if !(((backslashEscapes && style != ShellAlwaysQuotingStyle) ||
|
||||||
@ -353,26 +354,32 @@ func QuoteargBufferRestyled(
|
|||||||
goto StoreC
|
goto StoreC
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreEscape:
|
StoreEscape:
|
||||||
|
if elideOuterQuotes {
|
||||||
|
goto ForceOuterQuotingStyle
|
||||||
|
}
|
||||||
startESC()
|
startESC()
|
||||||
|
|
||||||
StoreC:
|
StoreC:
|
||||||
endESC()
|
endESC()
|
||||||
store(c)
|
store(c)
|
||||||
|
|
||||||
if !cAndShellQuoteCompat {
|
|
||||||
allCAndShellQuoteCompat = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len == 0 && style == ShellAlwaysQuotingStyle && elideOuterQuotes {
|
if quoteRune != 0 && !elideOuterQuotes {
|
||||||
|
store(quoteRune)
|
||||||
|
}
|
||||||
|
|
||||||
|
if style == ShellAlwaysQuotingStyle && elideOuterQuotes {
|
||||||
goto ForceOuterQuotingStyle
|
goto ForceOuterQuotingStyle
|
||||||
}
|
}
|
||||||
|
return buffer
|
||||||
|
|
||||||
ForceOuterQuotingStyle:
|
ForceOuterQuotingStyle:
|
||||||
if style == ShellAlwaysQuotingStyle && backslashEscapes {
|
if style == ShellAlwaysQuotingStyle && backslashEscapes {
|
||||||
style = ShellEscapeAlwaysQuotingStyle
|
style = ShellEscapeAlwaysQuotingStyle
|
||||||
}
|
}
|
||||||
QuoteargBufferRestyled(
|
return Quote(
|
||||||
buffer,
|
buffer,
|
||||||
arg,
|
arg,
|
||||||
style,
|
style,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user