1
0
mirror of https://github.com/go-task/task.git synced 2024-12-16 10:59:23 +02:00
task/vendor/github.com/mvdan/sh/interp/param.go

199 lines
3.7 KiB
Go
Raw Normal View History

2017-04-24 14:47:10 +02:00
// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information
package interp
import (
"path"
"strconv"
"strings"
"unicode"
"unicode/utf8"
"github.com/mvdan/sh/syntax"
)
func (r *Runner) paramExp(pe *syntax.ParamExp) string {
name := pe.Param.Value
var val varValue
set := false
switch name {
case "#":
val = strconv.Itoa(len(r.args))
case "*", "@":
val = strings.Join(r.args, " ")
case "?":
val = strconv.Itoa(r.exit)
default:
if n, err := strconv.Atoi(name); err == nil {
if i := n - 1; i < len(r.args) {
val, set = r.args[i], true
}
} else {
val, set = r.lookupVar(name)
}
}
str := varStr(val)
if pe.Ind != nil {
str = r.varInd(val, pe.Ind.Expr)
}
switch {
case pe.Length:
str = strconv.Itoa(utf8.RuneCountInString(str))
2017-05-01 00:50:22 +02:00
case pe.Indirect:
2017-04-24 14:47:10 +02:00
val, set = r.lookupVar(str)
str = varStr(val)
}
slicePos := func(expr syntax.ArithmExpr) int {
p := r.arithm(expr)
if p < 0 {
p = len(str) + p
if p < 0 {
p = len(str)
}
} else if p > len(str) {
p = len(str)
}
return p
}
if pe.Slice != nil {
if pe.Slice.Offset != nil {
offset := slicePos(pe.Slice.Offset)
str = str[offset:]
}
if pe.Slice.Length != nil {
length := slicePos(pe.Slice.Length)
str = str[:length]
}
}
if pe.Repl != nil {
orig := r.loneWord(pe.Repl.Orig)
with := r.loneWord(pe.Repl.With)
n := 1
if pe.Repl.All {
n = -1
}
str = strings.Replace(str, orig, with, n)
}
if pe.Exp != nil {
arg := r.loneWord(pe.Exp.Word)
switch pe.Exp.Op {
case syntax.SubstColPlus:
if str == "" {
break
}
fallthrough
case syntax.SubstPlus:
if set {
str = arg
}
case syntax.SubstMinus:
if set {
break
}
fallthrough
case syntax.SubstColMinus:
if str == "" {
str = arg
}
case syntax.SubstQuest:
if set {
break
}
fallthrough
case syntax.SubstColQuest:
if str == "" {
r.errf("%s", arg)
r.exit = 1
r.lastExit()
}
case syntax.SubstAssgn:
if set {
break
}
fallthrough
case syntax.SubstColAssgn:
if str == "" {
r.setVar(name, arg)
str = arg
}
case syntax.RemSmallPrefix:
str = removePattern(str, arg, false, false)
case syntax.RemLargePrefix:
str = removePattern(str, arg, false, true)
case syntax.RemSmallSuffix:
str = removePattern(str, arg, true, false)
case syntax.RemLargeSuffix:
str = removePattern(str, arg, true, true)
case syntax.UpperFirst:
rs := []rune(str)
if len(rs) > 0 {
rs[0] = unicode.ToUpper(rs[0])
}
str = string(rs)
case syntax.UpperAll:
str = strings.ToUpper(str)
case syntax.LowerFirst:
rs := []rune(str)
if len(rs) > 0 {
rs[0] = unicode.ToLower(rs[0])
}
str = string(rs)
case syntax.LowerAll:
str = strings.ToLower(str)
2017-05-01 00:50:22 +02:00
case syntax.OtherParamOps:
2017-04-24 14:47:10 +02:00
switch arg {
case "Q":
str = strconv.Quote(str)
case "E":
tail := str
var rns []rune
for tail != "" {
var rn rune
rn, _, tail, _ = strconv.UnquoteChar(tail, 0)
rns = append(rns, rn)
}
str = string(rns)
case "P", "A", "a":
r.errf("unhandled @%s param expansion", arg)
default:
r.errf("unexpected @%s param expansion", arg)
}
}
}
return str
}
func removePattern(str, pattern string, fromEnd, longest bool) string {
// TODO: really slow to not re-implement path.Match.
last := str
s := str
i := len(str)
if fromEnd {
i = 0
}
for {
if m, _ := path.Match(pattern, s); m {
last = str[i:]
if fromEnd {
last = str[:i]
}
if longest {
return last
}
}
if fromEnd {
if i++; i >= len(str) {
break
}
s = str[i:]
} else {
if i--; i < 1 {
break
}
s = str[:i]
}
}
return last
}