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.
staros/sysconf/sysconf.go

853 lines
21 KiB
Go

5 years ago
package sysconf
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"reflect"
"strconv"
"strings"
"sync"
)
type SysConf struct {
Data []*SysSegment
segmap map[string]int64
segId int64
HaveSegMent bool //是否有节这个概念
SegStart string
SegEnd string
CommentFlag []string //评论标识符,如#
EqualFlag string //赋值标识符,如=
ValueFlag string //值标识符,如"
EscapeFlag string //转义字符
CommentCR bool //评论是否能与value同一行true不行false可以
SpaceStr string //美化符号
lock sync.RWMutex
}
type SysSegment struct {
Name string
//nodeMap
Comment string
NodeData []*SysNode
nodeId int64
nodeMap map[string]int64
lock sync.RWMutex
}
type SysNode struct {
Key string
Value []string
Comment string
NoValue bool
lock sync.RWMutex
}
func NewIni() *SysConf {
ini := NewSysConf("=")
ini.CommentCR = true
ini.CommentFlag = []string{"#", ";"}
ini.HaveSegMent = true
ini.SegStart = "["
ini.SegEnd = "]"
ini.SpaceStr = " "
ini.EscapeFlag = "\\"
return ini
}
5 years ago
func NewSysConf(EqualFlag string) *SysConf {
syscnf := new(SysConf)
syscnf.EqualFlag = EqualFlag
return syscnf
}
// NewLinuxConf sysctl.conf like file
func NewLinuxConf(EqualFlag string) *SysConf {
syscnf := new(SysConf)
syscnf.EqualFlag = EqualFlag
syscnf.HaveSegMent = false
syscnf.CommentCR = true
syscnf.CommentFlag = []string{"#"}
return syscnf
}
func (syscfg *SysConf) ParseFromFile(filepath string) error {
data, err := ioutil.ReadFile(filepath)
if err != nil {
return err
}
3 years ago
return syscfg.Parse(data)
5 years ago
}
// Parse 生成INI文件结构
func (syscfg *SysConf) Parse(data []byte) error {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if syscfg.HaveSegMent && (syscfg.SegStart == "" || syscfg.SegEnd == "") {
return errors.New("SegMent Start or End Flag Not Allowed!")
}
if !syscfg.CommentCR {
return syscfg.parseNOCRComment(data)
}
return syscfg.parseCRComment(data)
}
func (syscfg *SysConf) parseNOCRComment(data []byte) error { //允许comment在同一行
data = bytes.TrimSpace(data)
dataLists := bytes.Split(data, []byte("\n"))
seg := new(SysSegment)
seg.nodeMap = make(map[string]int64)
syscfg.segmap = make(map[string]int64)
if syscfg.HaveSegMent {
seg.Name = "unnamed"
}
syscfg.segId = 0
var node *SysNode
for _, v1 := range dataLists {
var (
isSegStart bool = false
isEscape bool = false
isEqual bool = false
isComment bool = false
tsuMo string = ""
)
cowStr := strings.TrimSpace(string(v1))
for i := 0; i < len(cowStr); i++ {
runeStr := cowStr[i : i+1] //当前字符rune扫描
if runeStr == syscfg.EscapeFlag && (!isEscape) {
isEscape = true
continue
}
if runeStr == syscfg.SegStart && (!isEscape) {
isSegStart = true
continue
}
if runeStr == syscfg.SegEnd && (!isEscape) {
isSegStart = false
//New segment start from here
if seg.Name == "unnamed" && len(seg.NodeData) == 0 {
seg.Name = tsuMo
tsuMo = ""
continue
}
syscfg.segmap[seg.Name] = syscfg.segId
syscfg.segId++
syscfg.Data = append(syscfg.Data, seg)
seg = new(SysSegment)
seg.nodeMap = make(map[string]int64)
seg.Name = tsuMo
tsuMo = ""
continue
}
if isSegStart {
tsuMo += runeStr
if isEscape {
isEscape = false
}
continue
}
if syscfg.EqualFlag == runeStr && (!isEscape) && (!isEqual) {
key := strings.TrimSpace(tsuMo)
if val, ok := seg.nodeMap[key]; ok {
node = seg.NodeData[val]
} else {
node = new(SysNode)
node.Key = key
seg.nodeMap[node.Key] = seg.nodeId
seg.nodeId++
seg.NodeData = append(seg.NodeData, node)
}
tsuMo = ""
isEqual = true
if syscfg.ValueFlag != "" {
nokoriStr := strings.TrimSpace(cowStr[i+1:])
isFound := false
isValue := false
for k4, v4 := range nokoriStr {
if string([]rune{v4}) == syscfg.ValueFlag {
isValue = !isValue
}
if SliceIn(syscfg.CommentFlag, string([]rune{v4})) && !isValue {
val := nokoriStr[:k4]
isFound = true
startFinder := strings.Index(val, syscfg.ValueFlag)
endFinder := strings.LastIndex(val, syscfg.ValueFlag)
if !((startFinder == -1 || endFinder == -1) || (endFinder-startFinder <= 0)) {
node.Value = append(node.Value, strings.TrimSpace(val[startFinder+1:endFinder]))
}
node.Comment = nokoriStr[k4+1:] + "\n"
}
}
if !isFound {
startFinder := strings.Index(nokoriStr, syscfg.ValueFlag)
endFinder := strings.LastIndex(nokoriStr, syscfg.ValueFlag)
if (startFinder == -1 || endFinder == -1) || (endFinder-startFinder <= 0) {
break
}
node.Value = append(node.Value, strings.TrimSpace(nokoriStr[startFinder+1:endFinder]))
}
break
}
continue
}
if SliceIn(syscfg.CommentFlag, runeStr) && (!isEscape) {
isComment = true
if seg.nodeId == 0 {
seg.Comment += strings.TrimSpace(cowStr[i+1:]) + "\n"
break
}
if tsuMo != "" {
node.Value = append(node.Value, strings.TrimSpace(tsuMo))
tsuMo = ""
}
node.Comment += strings.TrimSpace(cowStr[i+1:]) + "\n"
break
}
isEscape = false
tsuMo += runeStr
}
if isEqual && tsuMo != "" {
node.Value = append(node.Value, strings.TrimSpace(tsuMo))
}
if !isEqual && tsuMo != "" && !isComment {
node = new(SysNode)
node.Key = tsuMo
seg.nodeMap[node.Key] = seg.nodeId
seg.nodeId++
seg.NodeData = append(seg.NodeData, node)
node.NoValue = true
}
}
if seg != nil {
syscfg.segmap[seg.Name] = syscfg.segId
syscfg.segId++
syscfg.Data = append(syscfg.Data, seg)
}
return nil
}
func (syscfg *SysConf) parseCRComment(data []byte) error { //不允许comment在同一行
data = bytes.TrimSpace(data)
dataLists := bytes.Split(data, []byte("\n"))
seg := new(SysSegment)
seg.nodeMap = make(map[string]int64)
syscfg.segmap = make(map[string]int64)
if syscfg.HaveSegMent {
seg.Name = "unnamed"
}
syscfg.segId = 0
var node *SysNode
for _, v1 := range dataLists {
var (
isSegStart bool = false
isEscape bool = false
isEqual bool = false
isComment bool = false
tsuMo string = ""
)
cowStr := strings.TrimSpace(string(v1))
for i := 0; i < len(cowStr); i++ {
runeStr := cowStr[i : i+1] //当前字符rune扫描
if runeStr == syscfg.EscapeFlag && (!isEscape) {
isEscape = true
continue
}
if runeStr == syscfg.SegStart && (!isEscape) {
isSegStart = true
continue
}
if runeStr == syscfg.SegEnd && (!isEscape) {
isSegStart = false
//New segment start from here
if seg.Name == "unnamed" && len(seg.NodeData) == 0 {
seg.Name = tsuMo
tsuMo = ""
break
}
syscfg.segmap[seg.Name] = syscfg.segId
syscfg.segId++
syscfg.Data = append(syscfg.Data, seg)
seg = new(SysSegment)
seg.nodeMap = make(map[string]int64)
seg.Name = tsuMo
tsuMo = ""
break
}
if isSegStart {
tsuMo += runeStr
if isEscape {
isEscape = false
}
continue
}
if syscfg.EqualFlag == runeStr && (!isEscape) && (!isEqual) {
key := strings.TrimSpace(tsuMo)
if val, ok := seg.nodeMap[key]; ok {
node = seg.NodeData[val]
} else {
node = new(SysNode)
node.Key = key
seg.nodeMap[node.Key] = seg.nodeId
seg.nodeId++
seg.NodeData = append(seg.NodeData, node)
}
tsuMo = ""
isEqual = true
if syscfg.ValueFlag == "" {
node.Value = append(node.Value, TrimEscape(strings.TrimSpace(cowStr[i+1:]), syscfg.EscapeFlag))
} else {
nokoriStr := strings.TrimSpace(cowStr[i+1:])
startFinder := strings.Index(nokoriStr, syscfg.ValueFlag)
endFinder := strings.LastIndex(nokoriStr, syscfg.ValueFlag)
if (startFinder == -1 || endFinder == -1) || (endFinder-startFinder <= 0) {
break
}
node.Value = append(node.Value, strings.TrimSpace(nokoriStr[startFinder+1:endFinder]))
}
break
}
if SliceIn(syscfg.CommentFlag, runeStr) && (!isEscape) {
isComment = true
tsuMo = ""
if seg.nodeId == 0 {
seg.Comment += strings.TrimSpace(cowStr[i+1:]) + "\n"
break
}
node.Comment += strings.TrimSpace(cowStr[i+1:]) + "\n"
break
}
isEscape = false
tsuMo += runeStr
}
if !isEqual && tsuMo != "" && !isComment {
node = new(SysNode)
node.Key = tsuMo
seg.nodeMap[node.Key] = seg.nodeId
seg.nodeId++
seg.NodeData = append(seg.NodeData, node)
node.NoValue = true
}
}
if seg != nil {
syscfg.segmap[seg.Name] = syscfg.segId
syscfg.segId++
syscfg.Data = append(syscfg.Data, seg)
}
return nil
}
func (syscfg *SysConf) Build() []byte {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
var outPut string
for _, v := range syscfg.Data {
if v == nil {
continue
}
if syscfg.HaveSegMent {
outPut += syscfg.SegStart + v.Name + syscfg.SegEnd + "\n"
}
if v.Comment != "" {
v.Comment = v.Comment[:len(v.Comment)-1]
comment := strings.Split(v.Comment, "\n")
for _, vc := range comment {
if vc != "" {
outPut += syscfg.CommentFlag[0] + vc + "\n"
} else {
outPut += "\n"
}
}
}
for _, v2 := range v.NodeData {
if v2 == nil {
continue
}
if v2.NoValue {
outPut += v2.Key + "\n"
} else {
for _, v3 := range v2.Value {
if syscfg.ValueFlag != "" {
outPut += v2.Key + syscfg.SpaceStr + syscfg.EqualFlag + syscfg.SpaceStr + syscfg.ValueFlag + v3 + syscfg.ValueFlag + "\n"
} else {
outPut += v2.Key + syscfg.SpaceStr + syscfg.EqualFlag + syscfg.SpaceStr + syscfg.addEscape(v3) + "\n"
}
}
if len(v2.Value) == 0 {
outPut += v2.Key + syscfg.SpaceStr + syscfg.EqualFlag + "\n"
}
if v2.Comment != "" {
v2.Comment = v2.Comment[:len(v2.Comment)-1]
comment := strings.Split(v2.Comment, "\n")
for _, vc := range comment {
if vc != "" {
outPut += syscfg.CommentFlag[0] + vc + "\n"
} else {
outPut += "\n"
}
}
}
}
}
}
return []byte(outPut)
}
func (syscfg *SysConf) addEscape(str string) string {
str = strings.ReplaceAll(str, syscfg.EscapeFlag, syscfg.EscapeFlag+syscfg.EscapeFlag)
str = strings.ReplaceAll(str, syscfg.EqualFlag, syscfg.EscapeFlag+syscfg.EqualFlag)
str = strings.ReplaceAll(str, syscfg.SegStart, syscfg.EscapeFlag+syscfg.SegStart)
str = strings.ReplaceAll(str, syscfg.SegEnd, syscfg.EscapeFlag+syscfg.SegEnd)
for _, v := range syscfg.CommentFlag {
str = strings.ReplaceAll(str, v, syscfg.EscapeFlag+v)
}
return str
}
func (syscfg *SysConf) Reverse() {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
for _, v := range syscfg.Data {
if v == nil {
continue
}
var (
NodeData []*SysNode
nodeId int64
nodeMap map[string]int64
)
nodeMap = make(map[string]int64)
for _, v2 := range v.NodeData {
if v2 == nil {
continue
}
for _, v3 := range v2.Value {
var node *SysNode
if val, ok := nodeMap[v3]; ok {
node = NodeData[val]
} else {
node = new(SysNode)
node.Key = v3
NodeData = append(NodeData, node)
nodeMap[v3] = nodeId
nodeId++
}
node.Value = append(node.Value, strings.TrimSpace(v2.Key))
node.Comment += v2.Comment
}
v.NodeData = NodeData
v.nodeId = nodeId
v.nodeMap = nodeMap
}
}
}
func TrimEscape(text, escape string) string {
var isEscape bool = false
var outPut []rune
if escape == "" {
return text
}
text = strings.TrimSpace(text)
for _, v := range text {
if v == []rune(escape)[0] && !isEscape {
isEscape = true
continue
}
outPut = append(outPut, v)
}
return string(outPut)
}
func SliceIn(slice interface{}, data interface{}) bool {
typed := reflect.ValueOf(slice)
if typed.Kind() == reflect.Slice || typed.Kind() == reflect.Array {
for i := 0; i < typed.Len(); i++ {
if typed.Index(i).Interface() == data {
return true
}
}
}
return false
}
// Unmarshal 输出结果到结构体中
func (cfg *SysConf) Unmarshal(ins interface{}) error {
4 years ago
var structSet func(t reflect.Type, v reflect.Value,oriSeg string) error
5 years ago
t := reflect.TypeOf(ins)
v := reflect.ValueOf(ins).Elem()
if v.Kind() != reflect.Struct {
return errors.New("Not a Struct")
}
if t.Kind() != reflect.Ptr || !v.CanSet() {
return errors.New("Cannot Write!")
}
t = t.Elem()
4 years ago
structSet = func(t reflect.Type, v reflect.Value,oriSeg string) error {
5 years ago
for i := 0; i < t.NumField(); i++ {
tp := t.Field(i)
vl := v.Field(i)
if !vl.CanSet() {
continue
}
if vl.Type().Kind() == reflect.Struct {
4 years ago
structSet(vl.Type(), vl,tp.Tag.Get("seg"))
5 years ago
continue
}
seg := tp.Tag.Get("seg")
key := tp.Tag.Get("key")
4 years ago
if oriSeg!="" {
seg=oriSeg
}
5 years ago
if seg == "" || key == "" {
continue
}
if _, ok := cfg.segmap[seg]; !ok {
continue
}
segs := cfg.Data[cfg.segmap[seg]]
if segs.Get(key) == "" {
continue
}
switch vl.Kind() {
case reflect.String:
vl.SetString(segs.Get(key))
case reflect.Int, reflect.Int32, reflect.Int64:
vl.SetInt(segs.Int64(key))
case reflect.Float32, reflect.Float64:
vl.SetFloat(segs.Float64(key))
case reflect.Bool:
vl.SetBool(segs.Bool(key))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
vl.SetUint(uint64(segs.Int64(key)))
default:
continue
}
}
return nil
}
4 years ago
return structSet(t, v,"")
5 years ago
}
// Marshal 输出结果到结构体中
func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
4 years ago
var structSet func(t reflect.Type, v reflect.Value,oriSeg string)
5 years ago
t := reflect.TypeOf(ins)
v := reflect.ValueOf(ins)
if v.Kind() != reflect.Struct {
return nil, errors.New("Not a Struct")
}
if t.Kind() == reflect.Ptr {
t = t.Elem()
v = v.Elem()
}
4 years ago
structSet = func(t reflect.Type, v reflect.Value,oriSeg string) {
5 years ago
for i := 0; i < t.NumField(); i++ {
var seg, key, comment string = "", "", ""
tp := t.Field(i)
vl := v.Field(i)
if vl.Type().Kind() == reflect.Struct {
4 years ago
structSet(vl.Type(), vl,tp.Tag.Get("seg"))
5 years ago
continue
}
seg = tp.Tag.Get("seg")
key = tp.Tag.Get("key")
comment = tp.Tag.Get("comment")
4 years ago
if oriSeg != "" {
seg=oriSeg
}
5 years ago
if seg == "" || key == "" {
continue
}
if _, ok := cfg.segmap[seg]; !ok {
cfg.AddSeg(seg)
}
cfg.Seg(seg).Set(key, fmt.Sprint(vl), comment)
}
}
4 years ago
structSet(t, v,"")
5 years ago
return cfg.Build(), nil
}
func (syscfg *SysConf) Seg(name string) *SysSegment {
if _, ok := syscfg.segmap[name]; !ok {
return nil
}
seg := syscfg.Data[syscfg.segmap[name]]
return seg
}
func (syscfg *SysConf) AddSeg(name string) *SysSegment {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if _, ok := syscfg.segmap[name]; !ok {
newseg := new(SysSegment)
newseg.Name = name
newseg.nodeMap = make(map[string]int64)
syscfg.Data = append(syscfg.Data, newseg)
syscfg.segId++
if syscfg.segmap == nil {
syscfg.segId = 0
syscfg.segmap = make(map[string]int64)
}
syscfg.segmap[newseg.Name] = syscfg.segId
return newseg
}
seg := syscfg.Data[syscfg.segmap[name]]
return seg
}
func (syscfg *SysConf) DeleteSeg(name string) error {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if _, ok := syscfg.segmap[name]; !ok {
return errors.New("Seg Not Exists")
}
syscfg.Data[syscfg.segmap[name]] = nil
delete(syscfg.segmap, name)
return nil
}
func (syscfg *SysSegment) GetComment(key string) string {
if v, ok := syscfg.nodeMap[key]; !ok {
return ""
} else {
return syscfg.NodeData[v].Comment
}
}
func (syscfg *SysSegment) SetComment(key, comment string) error {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if v, ok := syscfg.nodeMap[key]; !ok {
return errors.New("Key Not Exists")
} else {
syscfg.NodeData[v].Comment = comment
return nil
}
}
func (syscfg *SysSegment) Exist(key string) bool {
if _, ok := syscfg.nodeMap[key]; !ok {
return false
} else {
return true
}
}
func (syscfg *SysSegment) Get(key string) string {
if v, ok := syscfg.nodeMap[key]; !ok {
return ""
} else {
if len(syscfg.NodeData[v].Value) >= 1 {
return syscfg.NodeData[v].Value[0]
}
}
return ""
}
func (syscfg *SysSegment) GetAll(key string) []string {
if v, ok := syscfg.nodeMap[key]; !ok {
return []string{}
} else {
return syscfg.NodeData[v].Value
}
}
func (syscfg *SysSegment) Int(key string) int {
val := syscfg.Get(key)
if val == "" {
return 0
}
res, _ := strconv.Atoi(val)
return res
}
func (syscfg *SysSegment) Int64(key string) int64 {
val := syscfg.Get(key)
if val == "" {
return 0
}
res, _ := strconv.ParseInt(val, 10, 64)
return res
}
func (syscfg *SysSegment) Int32(key string) int32 {
val := syscfg.Get(key)
if val == "" {
return 0
}
res, _ := strconv.ParseInt(val, 10, 32)
return int32(res)
}
func (syscfg *SysSegment) Float64(key string) float64 {
val := syscfg.Get(key)
if val == "" {
return 0
}
res, _ := strconv.ParseFloat(val, 64)
return res
}
func (syscfg *SysSegment) Float32(key string) float32 {
val := syscfg.Get(key)
if val == "" {
return 0
}
res, _ := strconv.ParseFloat(val, 32)
return float32(res)
}
func (syscfg *SysSegment) Bool(key string) bool {
val := syscfg.Get(key)
if val == "" {
return false
}
res, _ := strconv.ParseBool(val)
return res
}
func (syscfg *SysSegment) SetBool(key string, value bool, comment string) error {
res := strconv.FormatBool(value)
return syscfg.Set(key, res, comment)
}
func (syscfg *SysSegment) SetFloat64(key string, prec int, value float64, comment string) error {
res := strconv.FormatFloat(value, 'f', prec, 64)
return syscfg.Set(key, res, comment)
}
func (syscfg *SysSegment) SetFloat32(key string, prec int, value float32, comment string) error {
res := strconv.FormatFloat(float64(value), 'f', prec, 32)
return syscfg.Set(key, res, comment)
}
func (syscfg *SysSegment) SetUint64(key string, value uint64, comment string) error {
res := strconv.FormatUint(value, 10)
return syscfg.Set(key, res, comment)
}
func (syscfg *SysSegment) SetInt64(key string, value int64, comment string) error {
res := strconv.FormatInt(value, 10)
return syscfg.Set(key, res, comment)
}
func (syscfg *SysSegment) SetInt32(key string, value int32, comment string) error {
res := strconv.FormatInt(int64(value), 10)
return syscfg.Set(key, res, comment)
}
func (syscfg *SysSegment) SetInt(key string, value int, comment string) error {
res := strconv.Itoa(value)
return syscfg.Set(key, res, comment)
}
func (syscfg *SysSegment) Set(key, value, comment string) error {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if v, ok := syscfg.nodeMap[key]; !ok {
node := new(SysNode)
node.Key = key
node.Value = append(node.Value, value)
node.Comment = comment
syscfg.NodeData = append(syscfg.NodeData, node)
syscfg.nodeMap[key] = syscfg.nodeId
syscfg.nodeId++
return nil
} else {
syscfg.NodeData[v].Value = []string{value}
if comment != "" {
syscfg.NodeData[v].Comment = comment
}
}
return nil
}
func (syscfg *SysSegment) SetAll(key string, value []string, comment string) error {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if v, ok := syscfg.nodeMap[key]; !ok {
node := new(SysNode)
node.Key = key
node.Value = value
node.Comment = comment
syscfg.NodeData = append(syscfg.NodeData, node)
syscfg.nodeMap[key] = syscfg.nodeId
syscfg.nodeId++
return nil
} else {
syscfg.NodeData[v].Value = value
if comment != "" {
syscfg.NodeData[v].Comment = comment
}
}
return nil
}
func (syscfg *SysSegment) AddValue(key, value, comment string) error {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if v, ok := syscfg.nodeMap[key]; !ok {
node := new(SysNode)
node.Key = key
node.Value = append(node.Value, value)
node.Comment = comment
syscfg.NodeData = append(syscfg.NodeData, node)
syscfg.nodeMap[key] = syscfg.nodeId
syscfg.nodeId++
return nil
} else {
syscfg.NodeData[v].Value = append(syscfg.NodeData[v].Value, value)
if comment != "" {
syscfg.NodeData[v].Comment = comment
}
}
return nil
}
func (syscfg *SysSegment) Delete(key string) error {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if v, ok := syscfg.nodeMap[key]; !ok {
return errors.New("Key not exists!")
} else {
if syscfg.NodeData[v].Comment != "" {
cmtSet := false
for j := v - 1; j >= 0; j-- {
if syscfg.NodeData[j] != nil {
syscfg.NodeData[j].Comment += syscfg.NodeData[v].Comment
cmtSet = true
break
}
}
if !cmtSet {
syscfg.Comment += syscfg.NodeData[v].Comment
}
}
syscfg.NodeData[v] = nil
delete(syscfg.nodeMap, key)
}
return nil
}
func (syscfg *SysSegment) DeleteValue(key string, Value string) error {
syscfg.lock.Lock()
defer syscfg.lock.Unlock()
if v, ok := syscfg.nodeMap[key]; !ok {
return errors.New("Key not exists!")
} else {
data := syscfg.NodeData[v].Value
var vals []string
for _, v := range data {
if v != Value {
vals = append(vals, v)
}
}
syscfg.NodeData[v].Value = vals
}
return nil
}