utils/text-util.go

287 lines
6.5 KiB
Go
Raw Permalink Normal View History

// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
2024-02-16 15:51:28 +01:00
// text-util.go
package utils
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/user"
"sort"
"strings"
"time"
)
type TextTemplate struct {
varMap map[string]string
UserName string
Uid string
ProgramDir string
HomeDir string
env map[string]string
}
func NewTextTemplate(args ...string) (instance *TextTemplate) {
instance = &TextTemplate{}
user, err := user.Current()
if err == nil {
instance.UserName = user.Username
instance.HomeDir = user.HomeDir
instance.Uid = user.Uid
}
instance.ProgramDir, _ = GetProgramDirPath()
instance.varMap = make(map[string]string, 5+len(args))
instance.initVarMap()
for _, arg := range args {
if len(arg) == 0 {
break
}
parts := strings.SplitN(arg, ":", 2)
if len(parts) == 2 {
instance.varMap[parts[0]] = parts[1]
} else {
instance.varMap[parts[0]] = ""
}
}
instance.env = make(map[string]string)
for _, v := range os.Environ() {
parts := strings.SplitN(v, "=", 2)
instance.env[parts[0]] = parts[1]
}
return
}
func (self *TextTemplate) initVarMap() {
self.varMap["dt"] = "Current timestamp as YYYY-MM-DD_HH-MM-SS"
self.varMap["ymd"] = "Current date as YYYY-MM-DD"
self.varMap["hm"] = "Current time as HH-MM"
self.varMap["h"] = "Current time as HH"
self.varMap["hms"] = "Current time as HH-MM-SS"
self.varMap["month"] = "Month name"
self.varMap["month-num"] = "Month as number (mm)"
self.varMap["week-day"] = "Week day name"
self.varMap["week-day-num"] = "Week day as number"
self.varMap["yesterday"] = "Yesterday date"
self.varMap["uid"] = self.Uid
self.varMap["username"] = self.UserName
self.varMap["home"] = self.HomeDir
self.varMap["progdir"] = self.ProgramDir
self.varMap["hostname"], _ = os.Hostname()
}
func (self *TextTemplate) AddVar(name, value string) {
self.varMap[name] = value
}
// func MakeVarMap() map[string]string {
// return map[string]string{
// "ymd": "Current date as YYYY-MM-DD",
// "hms": "Current time as HH-MM-SS",
// // "host": "Hostname",
// "uid": "UID",
// "username": "Username",
// "home": "Home directory",
// }
// }
func (self *TextTemplate) updateVarMap() {
var now = time.Now()
self.varMap["ymd"] = fmt.Sprintf("%04d-%02d-%02d", now.Year(), now.Month(), now.Day())
self.varMap["hms"] = fmt.Sprintf("%02d-%02d-%02d", now.Hour(), now.Minute(), now.Second())
self.varMap["hm"] = fmt.Sprintf("%02d-%02d", now.Hour(), now.Minute())
self.varMap["h"] = fmt.Sprintf("%02d", now.Hour())
self.varMap["month"] = now.Format("January")
self.varMap["month-num"] = fmt.Sprintf("%02d", now.Month())
self.varMap["week-day-num"] = fmt.Sprintf("%d", 1+now.Weekday())
self.varMap["week-day"] = now.Format("Monday")
self.varMap["dt"] = self.varMap["ymd"] + "_" + self.varMap["hms"]
yday := now.AddDate(0, 0, -1)
self.varMap["yesterday"] = fmt.Sprintf("%04d-%02d-%02d", yday.Year(), yday.Month(), yday.Day())
// self.varMap["uid"] = strconv.Itoa(int(self.Uid))
// self.varMap["uid"] = self.Uid
// self.varMap["username"] = self.UserName
// // self.varMap["host"] = self.Hostname
// self.varMap["home"] = self.HomeDir
}
func (self *TextTemplate) Expand(template string) string {
self.updateVarMap()
result := os.Expand(template, func(name string) string {
value, ok := self.varMap[name]
if ok {
return value
} else {
return ""
}
})
return result
}
func (self *TextTemplate) ExpandEnv(template string) (result string) {
if len(template) > 0 {
self.updateVarMap()
result = os.Expand(template, func(name string) string {
value, ok := self.varMap[name]
if ok {
return value
} else {
return "${" + name + "}"
}
})
// for k, v := range self.varMap {
// self.env[k] = v
// }
result = os.ExpandEnv(result)
// result = os.Expand(result, func(name string) string {
// value, ok := self.env[name]
// if ok {
// return value
// } else {
// return ""
// }
// })
}
return result
}
func (self *TextTemplate) Value(key string) (value string, ok bool) {
value, ok = self.varMap[key]
return
}
func (self *TextTemplate) String() string {
var sb strings.Builder
keys := make([]string, 0, len(self.varMap))
for k := range self.varMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
sb.WriteString(fmt.Sprintf("%s=%#v\n", k, self.varMap[k]))
}
// for k, v := range self.varMap {
// sb.WriteString(fmt.Sprintf("%s=%#v\n", k, v))
// }
return sb.String()
}
func ParseParamPairsFile(sourceFile string, separator string, hook func(line int, name, value string) (err error)) (err error) {
var source io.Reader
if source, err = os.Open(sourceFile); err == nil {
err = ParseParamPairs(source, separator, hook)
}
return
}
func ParseParamPairs(source io.Reader, separator string, hook func(line int, name, value string) (err error)) (err error) {
var content, sep, name, value []byte
var sb strings.Builder
if content, err = ioutil.ReadAll(source); err != nil {
return
}
if len(separator) == 0 {
sep = []byte{' '}
} else {
sep = []byte(separator)
}
for lineCount, rawLine := range bytes.Split(content, []byte{'\n'}) {
rawLine = bytes.TrimSpace(rawLine)
if len(rawLine) == 0 || rawLine[0] == '#' {
continue
}
parts := bytes.SplitN(rawLine, sep, 2)
name = bytes.TrimSpace(parts[0])
if len(parts) > 1 {
value = bytes.TrimSpace(parts[1])
} else {
value = []byte{}
}
quoteOn := false
escMode := false
sb.Reset()
for _, c := range value {
switch c {
case '"':
if escMode {
sb.WriteByte(c)
escMode = false
} else {
quoteOn = !quoteOn
}
case '\\':
if escMode {
sb.WriteByte(c)
escMode = false
} else {
escMode = true
}
case 'n':
if escMode {
sb.WriteByte('\n')
escMode = false
} else {
sb.WriteByte(c)
}
case 'r':
if escMode {
sb.WriteByte('\r')
escMode = false
} else {
sb.WriteByte(c)
}
case 't':
if escMode {
sb.WriteByte('\t')
escMode = false
} else {
sb.WriteByte(c)
}
case '#':
if quoteOn {
sb.WriteByte(c)
} else if escMode {
sb.WriteByte(c)
escMode = false
} else {
goto endloop
}
default:
if escMode {
escMode = false
}
sb.WriteByte(c)
}
}
endloop:
if err == nil && quoteOn {
err = errors.New("unbalanced quotes")
break
}
if err == nil {
if err = hook(lineCount, string(name), sb.String()); err != nil {
break
}
}
}
return
}