You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
envsubst/funcs.go

247 lines
5.2 KiB
Go

package envsubst
import (
"strconv"
"strings"
"unicode"
"unicode/utf8"
"git.awesome-for.me/liuzhiguo/envsubst/path"
)
// defines a parameter substitution function.
type substituteFunc func(string, ...string) string
// toLen returns the length of string s.
func toLen(s string, args ...string) string {
return strconv.Itoa(len(s))
}
// toLower returns a copy of the string s with all characters
// mapped to their lower case.
func toLower(s string, args ...string) string {
return strings.ToLower(s)
}
// toUpper returns a copy of the string s with all characters
// mapped to their upper case.
func toUpper(s string, args ...string) string {
return strings.ToUpper(s)
}
// toLowerFirst returns a copy of the string s with the first
// character mapped to its lower case.
func toLowerFirst(s string, args ...string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToLower(r)) + s[n:]
}
// toUpperFirst returns a copy of the string s with the first
// character mapped to its upper case.
func toUpperFirst(s string, args ...string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToUpper(r)) + s[n:]
}
// toDefault returns a copy of the string s if not empty, else
// returns a concatenation of the args without a separator.
func toDefault(s string, args ...string) string {
if len(s) == 0 && len(args) > 0 {
// don't use any separator
s = strings.Join(args, "")
}
return s
}
// toSubstr returns a slice of the string s at the specified
// length and position.
func toSubstr(s string, args ...string) string {
if len(args) == 0 {
return s // should never happen
}
pos, err := strconv.Atoi(args[0])
if err != nil {
// bash returns the string if the position
// cannot be parsed.
return s
}
if pos < 0 {
// if pos is negative (counts from the end) add it
// to length to get first character offset
pos = len(s) + pos
// if negative offset exceeds the length of the string
// start from 0
if pos < 0 {
pos = 0
}
}
if len(args) == 1 {
if pos < len(s) {
return s[pos:]
}
// if the position exceeds the length of the
// string an empty string is returned
return ""
}
length, err := strconv.Atoi(args[1])
if err != nil {
// bash returns the string if the length
// cannot be parsed.
return s
}
if pos+length >= len(s) {
if pos < len(s) {
// if the position exceeds the length of the
// string just return the rest of it like bash
return s[pos:]
}
// if the position exceeds the length of the
// string an empty string is returned
return ""
}
return s[pos : pos+length]
}
// replaceAll returns a copy of the string s with all instances
// of the substring replaced with the replacement string.
func replaceAll(s string, args ...string) string {
switch len(args) {
case 0:
return s
case 1:
return strings.Replace(s, args[0], "", -1)
default:
return strings.Replace(s, args[0], args[1], -1)
}
}
// replaceFirst returns a copy of the string s with the first
// instance of the substring replaced with the replacement string.
func replaceFirst(s string, args ...string) string {
switch len(args) {
case 0:
return s
case 1:
return strings.Replace(s, args[0], "", 1)
default:
return strings.Replace(s, args[0], args[1], 1)
}
}
// replacePrefix returns a copy of the string s with the matching
// prefix replaced with the replacement string.
func replacePrefix(s string, args ...string) string {
if len(args) != 2 {
return s
}
if strings.HasPrefix(s, args[0]) {
return strings.Replace(s, args[0], args[1], 1)
}
return s
}
// replaceSuffix returns a copy of the string s with the matching
// suffix replaced with the replacement string.
func replaceSuffix(s string, args ...string) string {
if len(args) != 2 {
return s
}
if strings.HasSuffix(s, args[0]) {
s = strings.TrimSuffix(s, args[0])
s = s + args[1]
}
return s
}
// TODO
func trimShortestPrefix(s string, args ...string) string {
if len(args) != 0 {
s = trimShortest(s, args[0])
}
return s
}
func trimShortestSuffix(s string, args ...string) string {
if len(args) != 0 {
r := reverse(s)
rarg := reverse(args[0])
s = reverse(trimShortest(r, rarg))
}
return s
}
func trimLongestPrefix(s string, args ...string) string {
if len(args) != 0 {
s = trimLongest(s, args[0])
}
return s
}
func trimLongestSuffix(s string, args ...string) string {
if len(args) != 0 {
r := reverse(s)
rarg := reverse(args[0])
s = reverse(trimLongest(r, rarg))
}
return s
}
func trimShortest(s, arg string) string {
var shortestMatch string
for i := 0; i < len(s); i++ {
match, err := path.Match(arg, s[0:len(s)-i])
if err != nil {
return s
}
if match {
shortestMatch = s[0 : len(s)-i]
}
}
if shortestMatch != "" {
return strings.TrimPrefix(s, shortestMatch)
}
return s
}
func trimLongest(s, arg string) string {
for i := 0; i < len(s); i++ {
match, err := path.Match(arg, s[0:len(s)-i])
if err != nil {
return s
}
if match {
return strings.TrimPrefix(s, s[0:len(s)-i])
}
}
return s
}
func reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}