package starainrt import ( "bufio" "errors" "fmt" "io" "io/ioutil" "os" "reflect" "regexp" "strconv" "strings" ) func ReWriteFileByKV(filepath, rem, conn, ret string, kv map[string]string) bool { var outputstr string var ataru bool = false if (!Exists(filepath)) || (!IsFile(filepath)) { return false } fso, err := os.Open(filepath) if err != nil { return false } rempar := regexp.MustCompile("^" + rem) buf := bufio.NewReader(fso) for { bytxt, _, eof := buf.ReadLine() if eof == io.EOF { break } txt := strings.TrimSpace(string(bytxt)) if rempar.Match([]byte(txt)) { outputstr += txt + ret continue } for k, v := range kv { keypar := regexp.MustCompile("^" + k) if keypar.Match([]byte(txt)) { ataru = true outputstr += k + conn + v + ret delete(kv, k) } } if ataru { ataru = false continue } else { outputstr += txt + ret } } fso.Close() if len(kv) != 0 { for k, v := range kv { outputstr += k + conn + v + ret delete(kv, k) } } err = ioutil.WriteFile(filepath, []byte(outputstr), 0755) if err != nil { return false } return true } func GetINIValue(filepath, rem, conn string, kv []string) (bool, map[string]string) { outputstr := make(map[string]string) if (!Exists(filepath)) || (!IsFile(filepath)) { return false, outputstr } fso, err := os.Open(filepath) if err != nil { return false, outputstr } rempar := regexp.MustCompile("^" + rem) buf := bufio.NewReader(fso) for { bytxt, _, eof := buf.ReadLine() if eof == io.EOF { break } txt := strings.TrimSpace(string(bytxt)) if rempar.Match([]byte(txt)) { continue } var i int = 0 var v2 string for k, v := range kv { if v == "" { continue } v2 = "" for _, b := range []byte(v) { switch string(b) { case ".": v2 += "\\." case "\\": v2 += "\\" case "-": v2 += "\\-" case "(": v2 += "\\(" case ")": v2 += "\\)" case "{": v2 += "\\{" case "}": v2 += "\\}" case "[": v2 += "\\[" case "]": v2 += "\\]" case "$": v2 += "\\]$" case "^": v2 += "\\^" default: v2 += string(b) } } keypar := regexp.MustCompile("^" + v2 + ".*?" + conn + "(.*?)" + "(" + rem + "|$)") if keypar.Match([]byte(txt)) { i++ kekka := keypar.FindSubmatch([]byte(txt)) outputstr[v] = string(kekka[1]) kv[k] = "" } } if i != len(kv) { for _, v := range kv { if v != "" { outputstr[v] = "" } } } } return true, outputstr } func ReadINIConfig(filepath string) (map[string]map[string]string, error) { var result map[string]map[string]string result = make(map[string]map[string]string) if !Exists(filepath) { return result, errors.New("file not exists") } data, err := ioutil.ReadFile(filepath) if err != nil { return result, nil } strdata := string(data) datas := strings.Split(strdata, "\n") var inseg, nolabel bool = false, false var segname string jump: if nolabel { segname = "unnamed" inseg = true } for _, v := range datas { v = strings.TrimSpace(v) if ok, _ := regexp.MatchString("^#", v); ok { continue } segfind := regexp.MustCompile(`^\[(.*)\]`) if !inseg { if ok, _ := regexp.MatchString(`(.*?)=(.*)`, v); ok { nolabel = true goto jump } if !segfind.MatchString(v) { continue } else { tmp := segfind.FindStringSubmatch(v) segname = tmp[1] inseg = true } } else { if segfind.MatchString(v) { tmp := segfind.FindStringSubmatch(v) segname = tmp[1] inseg = true } } if fn := strings.Index(v, "#"); fn >= 0 { v = v[0:fn] } if ok, _ := regexp.MatchString(`(.*?)=(.*)`, v); ok { regtmp := regexp.MustCompile(`(.*?)=(.*)`) tmp := regtmp.FindStringSubmatch(v) if result[segname] == nil { result[segname] = make(map[string]string) } result[segname][strings.TrimSpace(tmp[1])] = strings.TrimSpace(tmp[2]) } else { continue } } return result, nil } type StarCfg struct { Data []*CfgSegment segmap map[string]int //nodemap map[int]map[string]int segid int } type CfgNode struct { Key string Value string Comment string } type CfgSegment struct { Name string cmap map[string]int Comment string Node []*CfgNode nodeid int //InsertNode []*CfgNode } func (this *StarCfg) ParseFromFile(filepath string) error { if !Exists(filepath) { return errors.New(filepath + " 不存在") } data, err := ioutil.ReadFile(filepath) if err != nil { return err } this.Parse(data) return nil } func (this *StarCfg) WriteToFile(filepath string) error { data := this.Build() return ioutil.WriteFile(filepath, data, 0644) } // Parse 生成INI文件结构 func (this *StarCfg) Parse(data []byte) { var newnode *CfgNode this.segid = 0 //segment序号 nodeint := 0 this.segmap = make(map[string]int) //segment名 序号 //this.nodemap = make(map[int]map[string]int) nodemap := make(map[string]int) strdata := string(data) //转换成字符串 list := strings.Split(strdata, "\n") //分割 newseg := new(CfgSegment) newseg.Name = "unnamed" //默认名 //newseg.InsertNode = []*CfgNode{} this.segmap["unnamed"] = 0 lastiseg := true for _, v := range list { istrans := false isseg := false //是否为新seg isnote := false //是否为注释 isequal := false // 是否为等号 tmp1 := []rune{} tmp2 := []rune{} note := []rune{} v = strings.TrimSpace(v) if len(v) > 0 && v[0:1] == ";" { isnote = true //首字母是;时,代表注释 } for k, v2 := range v { if k == 0 { if v2 == '[' { isseg = true continue } } if v2 == '=' && (!istrans && !isnote && !isequal) { isequal = true continue } if v2 == ']' && (!istrans && !isnote) { continue } if v2 == '#' && (!istrans && !isnote) { isnote = true continue } if v2 == '\\' && (!istrans && !isnote) { istrans = true continue } if istrans { istrans = false } if !isnote && (!isequal) { tmp1 = append(tmp1, v2) } else if !isnote && isequal { tmp2 = append(tmp2, v2) } else if isnote { note = append(note, v2) } } if isseg { this.Data = append(this.Data, newseg) newseg.nodeid = nodeint //newseg.cmap = make(map[string]int) newseg.cmap = nodemap nodemap = make(map[string]int) newseg = new(CfgSegment) //newseg.InsertNode = []*CfgNode{} newseg.Name = strings.TrimSpace(string(tmp1)) if isnote { newseg.Comment = strings.TrimSpace(string(note)) } this.segid++ this.segmap[newseg.Name] = this.segid nodeint = 0 lastiseg = true continue } if isequal { newnode = new(CfgNode) newnode.Key = strings.TrimSpace(string(tmp1)) newnode.Value = strings.TrimSpace(string(tmp2)) if isnote { newnode.Comment = strings.TrimSpace(string(note)) } newseg.Node = append(newseg.Node, newnode) nodemap[newnode.Key] = nodeint nodeint++ lastiseg = false continue } if isnote { comment := strings.TrimSpace(string(note)) if lastiseg { newseg.Comment += "\n" + comment } else { newnode.Comment += "\n" + comment } continue } } newseg.nodeid = nodeint //newseg.cmap = make(map[string]int) newseg.cmap = nodemap this.Data = append(this.Data, newseg) } // Unmarshal 输出结果到结构体中 func (cfg *StarCfg) Unmarshal(ins interface{}) error { var structSet func(t reflect.Type, v reflect.Value) error 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() structSet = func(t reflect.Type, v reflect.Value) error { 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 { structSet(vl.Type(), vl) continue } seg := tp.Tag.Get("seg") key := tp.Tag.Get("key") 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 } return structSet(t, v) } // Marshal 输出结果到结构体中 func (cfg *StarCfg) Marshal(ins interface{}) ([]byte, error) { var structSet func(t reflect.Type, v reflect.Value) 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() } structSet = func(t reflect.Type, v reflect.Value) { 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 { structSet(vl.Type(), vl) continue } seg = tp.Tag.Get("seg") key = tp.Tag.Get("key") comment = tp.Tag.Get("comment") if seg == "" || key == "" { continue } if _, ok := cfg.segmap[seg]; !ok { cfg.AddSeg(seg) } cfg.Seg(seg).Set(key, fmt.Sprint(vl), comment) } } structSet(t, v) return cfg.Build(), nil } func (this *StarCfg) Seg(name string) *CfgSegment { if _, ok := this.segmap[name]; !ok { return nil } seg := this.Data[this.segmap[name]] return seg } func (cfg *StarCfg) AddSeg(name string) *CfgSegment { if _, ok := cfg.segmap[name]; !ok { newseg := new(CfgSegment) newseg.Name = name newseg.cmap = make(map[string]int) cfg.Data = append(cfg.Data, newseg) cfg.segid++ if cfg.segmap == nil { cfg.segid = 0 cfg.segmap = make(map[string]int) } cfg.segmap[newseg.Name] = cfg.segid return newseg } seg := cfg.Data[cfg.segmap[name]] return seg } func (cfg *StarCfg) DeleteSeg(name string) error { if _, ok := cfg.segmap[name]; !ok { return errors.New("Seg Not Exists") } cfg.Data[cfg.segmap[name]] = nil delete(cfg.segmap, name) return nil } func (this *StarCfg) Build() []byte { var res, comm string for _, v := range this.Data { comm = "" if v == nil { continue } if v.Name != "unnamed" { res += `[ ` + this.repkv(v.Name) + ` ]` } if v.Comment != "" { comm = strings.Replace(v.Comment, "\n", "\n#", -1) if comm[0:1] != "\n" { comm = " #" + comm } } res += comm + "\n" for _, v2 := range v.Node { comm = "" if v2 == nil { continue } res += this.repkv(v2.Key) + " = " + this.repkv(v2.Value) if v2.Comment != "" { comm = strings.Replace(v2.Comment, "\n", "\n#", -1) if comm[0:1] != "\n" { comm = " #" + comm } } res += comm + "\n" } } return []byte(strings.TrimSpace(res)) } func (this *StarCfg) repkv(value string) string { value = strings.Replace(value, `\`, `\\`, -1) value = strings.Replace(value, `#`, `\#`, -1) //value = strings.Replace(value, `=`, `\=`, -1) value = strings.Replace(value, `[`, `\[`, -1) value = strings.Replace(value, `]`, `\]`, -1) return value } func (this *CfgSegment) GetComment(key string) string { if v, ok := this.cmap[key]; !ok { return "" } else { return this.Node[v].Comment } } func (this *CfgSegment) SetComment(key, comment string) error { if v, ok := this.cmap[key]; !ok { return errors.New("Key Not Exists") } else { this.Node[v].Comment = comment return nil } } func (this *CfgSegment) Exist(key string) bool { if _, ok := this.cmap[key]; !ok { return false } else { return true } } func (this *CfgSegment) Get(key string) string { if v, ok := this.cmap[key]; !ok { return "" } else { return this.Node[v].Value } } func (this *CfgSegment) Int(key string) int { val := this.Get(key) if val == "" { return 0 } res, _ := strconv.Atoi(val) return res } func (this *CfgSegment) Int64(key string) int64 { val := this.Get(key) if val == "" { return 0 } res, _ := strconv.ParseInt(val, 10, 64) return res } func (this *CfgSegment) Int32(key string) int32 { val := this.Get(key) if val == "" { return 0 } res, _ := strconv.ParseInt(val, 10, 32) return int32(res) } func (this *CfgSegment) Float64(key string) float64 { val := this.Get(key) if val == "" { return 0 } res, _ := strconv.ParseFloat(val, 64) return res } func (this *CfgSegment) Float32(key string) float32 { val := this.Get(key) if val == "" { return 0 } res, _ := strconv.ParseFloat(val, 32) return float32(res) } func (this *CfgSegment) Bool(key string) bool { val := this.Get(key) if val == "" { return false } res, _ := strconv.ParseBool(val) return res } func (this *CfgSegment) SetBool(key string, value bool, comment string) error { res := strconv.FormatBool(value) return this.Set(key, res, comment) } func (this *CfgSegment) SetFloat64(key string, prec int, value float64, comment string) error { res := strconv.FormatFloat(value, 'f', prec, 64) return this.Set(key, res, comment) } func (this *CfgSegment) SetFloat32(key string, prec int, value float32, comment string) error { res := strconv.FormatFloat(float64(value), 'f', prec, 32) return this.Set(key, res, comment) } func (this *CfgSegment) SetInt64(key string, value int64, comment string) error { res := strconv.FormatInt(value, 10) return this.Set(key, res, comment) } func (this *CfgSegment) SetInt32(key string, value int32, comment string) error { res := strconv.FormatInt(int64(value), 10) return this.Set(key, res, comment) } func (this *CfgSegment) SetInt(key string, value int, comment string) error { res := strconv.Itoa(value) return this.Set(key, res, comment) } func (this *CfgSegment) Set(key, value, comment string) error { if v, ok := this.cmap[key]; !ok { node := new(CfgNode) node.Key = key node.Value = value node.Comment = comment this.Node = append(this.Node, node) this.cmap[key] = this.nodeid this.nodeid++ return nil } else { this.Node[v].Value = value if comment != "" { this.Node[v].Comment = comment } } return nil } func (this *CfgSegment) Delete(key string) error { if v, ok := this.cmap[key]; !ok { return errors.New("Key not exists!") } else { this.Node[v] = nil delete(this.cmap, key) } return nil }