0.1
This commit is contained in:
parent
753cb7bfd6
commit
294a89ba74
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Binaries for programs and plugins
|
||||
bin/*
|
||||
multini
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Custom binary test
|
||||
tests/out_ini/*
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
73
Makefile
Normal file
73
Makefile
Normal file
@ -0,0 +1,73 @@
|
||||
NAME=multini
|
||||
VERSION=0.1
|
||||
GOCMD=go
|
||||
LDFLAGS:="$(LDFLAGS) -X 'main.Version=$(VERSION)'"
|
||||
GOBUILD=$(GOCMD) build -ldflags=$(LDFLAGS)
|
||||
SRCMAIN=.
|
||||
BINDIR=bin
|
||||
BIN=$(BINDIR)/$(NAME)
|
||||
README=README
|
||||
LICENSE=LICENSE
|
||||
TEST=./run_test.sh
|
||||
PREFIX=/usr
|
||||
|
||||
all: build
|
||||
|
||||
prep: clean
|
||||
mkdir $(BINDIR)
|
||||
|
||||
build: prep
|
||||
$(GOBUILD) -o $(BIN) $(SRCMAIN)
|
||||
|
||||
check-build:
|
||||
test -e $(BIN)
|
||||
|
||||
freebsd-386: prep
|
||||
GOOS=freebsd GOARCH=386 $(GOBUILD) -o $(BIN)-freebsd-386 $(SRCMAIN)
|
||||
|
||||
darwin-386: prep
|
||||
GOOS=darwin GOARCH=386 $(GOBUILD) -o $(BIN)-darwin-386 $(SRCMAIN)
|
||||
|
||||
linux-386: prep
|
||||
GOOS=linux GOARCH=386 $(GOBUILD) -o $(BIN)-linux-386 $(SRCMAIN)
|
||||
|
||||
windows-386: prep
|
||||
GOOS=windows GOARCH=386 $(GOBUILD) -o $(BIN)-windows-386.exe $(SRCMAIN)
|
||||
|
||||
freebsd-amd64: prep
|
||||
GOOS=freebsd GOARCH=amd64 $(GOBUILD) -o $(BIN)-freebsd-amd64 $(SRCMAIN)
|
||||
|
||||
darwin-amd64: prep
|
||||
GOOS=darwin GOARCH=amd64 $(GOBUILD) -o $(BIN)-darwin-amd64 $(SRCMAIN)
|
||||
|
||||
linux-amd64: prep
|
||||
GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BIN)-linux-amd64 $(SRCMAIN)
|
||||
|
||||
windows-amd64: prep
|
||||
GOOS=windows GOARCH=amd64 $(GOBUILD) -o $(BIN)-windows-amd64.exe $(SRCMAIN)
|
||||
|
||||
compile: freebsd-386 darwin-386 linux-386 windows-386 freebsd-amd64 darwin-amd64 linux-amd64 windows-amd64
|
||||
|
||||
install: check-build
|
||||
install -m 755 -d $(PREFIX)/bin/
|
||||
install -m 755 $(BIN) $(PREFIX)/bin/
|
||||
install -m 755 -d $(PREFIX)/share/licenses/$(NAME)/
|
||||
install -m 644 $(LICENSE) $(PREFIX)/share/licenses/$(NAME)/
|
||||
install -m 755 -d $(PREFIX)/share/doc/$(NAME)/
|
||||
install -m 644 $(README) $(PREFIX)/share/doc/$(NAME)/
|
||||
|
||||
check-install:
|
||||
test -e $(PREFIX)/bin/$(NAME) || \
|
||||
test -d $(PREFIX)/share/licenses/$(NAME) || \
|
||||
test -d $(PREFIX)/share/doc/$(NAME)
|
||||
|
||||
uninstall: check-install
|
||||
rm -f $(PREFIX)/bin/$(NAME)
|
||||
rm -rf $(PREFIX)/share/licenses/$(NAME)
|
||||
rm -rf $(PREFIX)/share/doc/$(NAME)
|
||||
|
||||
clean:
|
||||
rm -rf $(BINDIR)
|
||||
|
||||
test: check-build
|
||||
$(TEST) $(BIN)
|
22
README
Normal file
22
README
Normal file
@ -0,0 +1,22 @@
|
||||
A utility for manipulating ini files with duplicate keys
|
||||
|
||||
Usage: multini [OPTION]... [ACTION] config_file [section] [param] [value]
|
||||
Actions:
|
||||
-g, --get get values for a given combination of parameters.
|
||||
-s, --set set values for a given combination of parameters.
|
||||
-a, --add add values for a given combination of parameters.
|
||||
-d, --del delete the given combination of parameters.
|
||||
-c, --chk display parsing errors for the specified file.
|
||||
|
||||
Options:
|
||||
-e, --existing For --set and --del, fail if item is missing.
|
||||
-i, --inplace Lock and write files in place.
|
||||
This is not atomic but has less restrictions
|
||||
than the default replacement method.
|
||||
-o, --output FILE Write output to FILE instead. '-' means stdout
|
||||
-u, --unix Use LF as end of line
|
||||
-w, --windows Use CRLF as end of line
|
||||
-h, --help Write this help to stdout
|
||||
--version Write version to stdout
|
||||
|
||||
2020 (c) GenZmeY
|
68
actions.go
Normal file
68
actions.go
Normal file
@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"multini/output"
|
||||
"multini/types"
|
||||
)
|
||||
|
||||
func chk() int {
|
||||
var ok bool
|
||||
var err error
|
||||
ok, err = iniCheck(ArgFile)
|
||||
if err != nil {
|
||||
output.Errorln(err)
|
||||
return EXIT_FILE_READ_ERR
|
||||
}
|
||||
if ok {
|
||||
return EXIT_SUCCESS
|
||||
} else {
|
||||
return EXIT_BAD_SYNTAX_ERR
|
||||
}
|
||||
}
|
||||
|
||||
func add(ini *types.Ini) error {
|
||||
if ArgKeyIsSet {
|
||||
return ini.AddKey(ArgSection, ArgKey, ArgValue)
|
||||
} else {
|
||||
ini.AddSection(ArgSection)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func set(ini *types.Ini) error {
|
||||
if ArgKeyIsSet {
|
||||
return ini.SetKey(ArgSection, ArgKey, ArgValue)
|
||||
} else {
|
||||
ini.SetSection(ArgSection)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func get(ini *types.Ini) error {
|
||||
var err error = nil
|
||||
var res string
|
||||
if ArgValueIsSet {
|
||||
return ini.GetKeyVal(ArgSection, ArgKey, ArgValue)
|
||||
} else if ArgKeyIsSet {
|
||||
res, err = ini.GetKey(ArgSection, ArgKey)
|
||||
} else if ArgSectionIsSet {
|
||||
res, err = ini.GetSection(ArgSection)
|
||||
} else {
|
||||
res = ini.Get()
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
output.Println(res)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func del(ini *types.Ini) error {
|
||||
if ArgValueIsSet {
|
||||
return ini.DelKeyVal(ArgSection, ArgKey, ArgValue)
|
||||
} else if ArgKeyIsSet {
|
||||
return ini.DelKey(ArgSection, ArgKey)
|
||||
} else {
|
||||
return ini.DelSection(ArgSection)
|
||||
}
|
||||
}
|
177
args.go
Normal file
177
args.go
Normal file
@ -0,0 +1,177 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"multini/output"
|
||||
"multini/types"
|
||||
|
||||
"github.com/juju/gnuflag"
|
||||
)
|
||||
|
||||
var (
|
||||
ArgInplace bool
|
||||
ArgGet bool
|
||||
ArgSet bool
|
||||
ArgAdd bool
|
||||
ArgDel bool
|
||||
ArgChk bool
|
||||
ArgVerbose bool
|
||||
ArgVersion bool
|
||||
ArgWindows bool
|
||||
ArgUnix bool
|
||||
ArgHelp bool
|
||||
ArgExisting bool
|
||||
ArgOutput string
|
||||
|
||||
ArgFile string
|
||||
ArgFileIsSet bool = false
|
||||
ArgSection string
|
||||
ArgSectionIsSet bool = false
|
||||
ArgKey string
|
||||
ArgKeyIsSet bool = false
|
||||
ArgValue string
|
||||
ArgValueIsSet bool = false
|
||||
)
|
||||
|
||||
func printHelp() {
|
||||
output.Println("A utility for manipulating ini files with duplicate keys")
|
||||
output.Println("")
|
||||
output.Println("Usage: multini [OPTION]... [ACTION] config_file [section] [param] [value]")
|
||||
output.Println("Actions:")
|
||||
output.Println(" -g, --get get values for a given combination of parameters.")
|
||||
output.Println(" -s, --set set values for a given combination of parameters.")
|
||||
output.Println(" -a, --add add values for a given combination of parameters.")
|
||||
output.Println(" -d, --del delete the given combination of parameters.")
|
||||
output.Println(" -c, --chk display parsing errors for the specified file.")
|
||||
output.Println("")
|
||||
output.Println("Options:")
|
||||
output.Println(" -e, --existing For --set and --del, fail if item is missing.")
|
||||
output.Println(" -i, --inplace Lock and write files in place.")
|
||||
output.Println(" This is not atomic but has less restrictions")
|
||||
output.Println(" than the default replacement method.")
|
||||
output.Println(" -o, --output FILE Write output to FILE instead. '-' means stdout")
|
||||
// output.Println(" -v, --verbose Indicate on stderr if changes were made")
|
||||
output.Println(" -u, --unix Use LF as end of line")
|
||||
output.Println(" -w, --windows Use CRLF as end of line")
|
||||
output.Println(" -h, --help Write this help to stdout")
|
||||
output.Println(" --version Write version to stdout")
|
||||
}
|
||||
|
||||
func printVersion() {
|
||||
output.Println("multini ", Version)
|
||||
}
|
||||
|
||||
func init() {
|
||||
gnuflag.BoolVar(&ArgGet, "get", false, "")
|
||||
gnuflag.BoolVar(&ArgGet, "g", false, "")
|
||||
gnuflag.BoolVar(&ArgAdd, "add", false, "")
|
||||
gnuflag.BoolVar(&ArgAdd, "a", false, "")
|
||||
gnuflag.BoolVar(&ArgSet, "set", false, "")
|
||||
gnuflag.BoolVar(&ArgSet, "s", false, "")
|
||||
gnuflag.BoolVar(&ArgDel, "del", false, "")
|
||||
gnuflag.BoolVar(&ArgDel, "d", false, "")
|
||||
gnuflag.BoolVar(&ArgChk, "chk", false, "")
|
||||
gnuflag.BoolVar(&ArgChk, "c", false, "")
|
||||
gnuflag.BoolVar(&ArgDel, "inplace", false, "")
|
||||
gnuflag.BoolVar(&ArgDel, "i", false, "")
|
||||
gnuflag.BoolVar(&ArgUnix, "unix", false, "")
|
||||
gnuflag.BoolVar(&ArgUnix, "u", false, "")
|
||||
gnuflag.BoolVar(&ArgWindows, "windows", false, "")
|
||||
gnuflag.BoolVar(&ArgWindows, "w", false, "")
|
||||
gnuflag.BoolVar(&ArgExisting, "existing", false, "")
|
||||
gnuflag.BoolVar(&ArgExisting, "e", false, "")
|
||||
gnuflag.BoolVar(&ArgVerbose, "verbose", false, "")
|
||||
gnuflag.BoolVar(&ArgVerbose, "v", false, "")
|
||||
gnuflag.StringVar(&ArgOutput, "output", "", "")
|
||||
gnuflag.StringVar(&ArgOutput, "o", "", "")
|
||||
gnuflag.BoolVar(&ArgVersion, "version", false, "")
|
||||
gnuflag.BoolVar(&ArgHelp, "help", false, "")
|
||||
gnuflag.BoolVar(&ArgHelp, "h", false, "")
|
||||
}
|
||||
|
||||
func parseArgs() error {
|
||||
gnuflag.Parse(true)
|
||||
|
||||
// info
|
||||
switch {
|
||||
case ArgHelp:
|
||||
printHelp()
|
||||
os.Exit(EXIT_SUCCESS)
|
||||
case ArgVersion:
|
||||
printVersion()
|
||||
os.Exit(EXIT_SUCCESS)
|
||||
}
|
||||
|
||||
// File EOF
|
||||
switch {
|
||||
case ArgWindows:
|
||||
types.SetEndOfLineWindows()
|
||||
case ArgUnix:
|
||||
types.SetEndOfLineUnix()
|
||||
default:
|
||||
types.SetEndOfLineNative()
|
||||
}
|
||||
|
||||
// Output settings
|
||||
output.SetEndOfLineNative()
|
||||
output.SetVerbose(ArgVerbose)
|
||||
|
||||
// Positional Args
|
||||
for i := 0; i < 4 && i < gnuflag.NArg(); i++ {
|
||||
switch i {
|
||||
case 0:
|
||||
ArgFile = gnuflag.Arg(0)
|
||||
ArgFileIsSet = true
|
||||
case 1:
|
||||
ArgSection = gnuflag.Arg(1)
|
||||
ArgSectionIsSet = true
|
||||
case 2:
|
||||
ArgKey = gnuflag.Arg(2)
|
||||
ArgKeyIsSet = true
|
||||
case 3:
|
||||
ArgValue = gnuflag.Arg(3)
|
||||
ArgValueIsSet = true
|
||||
}
|
||||
}
|
||||
|
||||
if !ArgFileIsSet {
|
||||
return errors.New("Config_file not specified")
|
||||
}
|
||||
|
||||
// Mode
|
||||
actionCounter := 0
|
||||
if ArgChk {
|
||||
actionCounter++
|
||||
}
|
||||
if ArgDel {
|
||||
actionCounter++
|
||||
if !ArgSectionIsSet {
|
||||
return errors.New("Section not specified")
|
||||
}
|
||||
}
|
||||
if ArgGet {
|
||||
actionCounter++
|
||||
}
|
||||
if ArgSet {
|
||||
actionCounter++
|
||||
if !ArgSectionIsSet {
|
||||
return errors.New("Section not specified")
|
||||
}
|
||||
}
|
||||
if ArgAdd {
|
||||
actionCounter++
|
||||
if !ArgSectionIsSet {
|
||||
return errors.New("Section not specified")
|
||||
}
|
||||
}
|
||||
switch actionCounter {
|
||||
case 0:
|
||||
return errors.New("Action not set")
|
||||
case 1:
|
||||
return nil
|
||||
default:
|
||||
return errors.New("Only one action can be used at the same time")
|
||||
}
|
||||
}
|
80
main.go
Normal file
80
main.go
Normal file
@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"multini/output"
|
||||
"multini/types"
|
||||
)
|
||||
|
||||
const (
|
||||
EXIT_SUCCESS int = 0
|
||||
EXIT_ARG_ERR int = 1
|
||||
EXIT_FILE_READ_ERR int = 2
|
||||
EXIT_BAD_SYNTAX_ERR int = 3
|
||||
EXIT_ELEMENT_NOT_FOUND int = 4
|
||||
EXIT_FILE_WRITE_ERR int = 5
|
||||
EXIT_ACTION_ERR int = 6
|
||||
)
|
||||
|
||||
var (
|
||||
Version string = "development"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
var ini types.Ini
|
||||
|
||||
if err = parseArgs(); err != nil {
|
||||
output.Errorln(err)
|
||||
os.Exit(EXIT_ARG_ERR)
|
||||
}
|
||||
|
||||
if ArgChk {
|
||||
os.Exit(chk())
|
||||
}
|
||||
|
||||
ini, err = iniRead(ArgFile)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(EXIT_FILE_READ_ERR)
|
||||
}
|
||||
|
||||
switch {
|
||||
case ArgGet:
|
||||
err = get(&ini)
|
||||
case ArgAdd:
|
||||
err = add(&ini)
|
||||
case ArgDel:
|
||||
err = del(&ini)
|
||||
case ArgSet:
|
||||
err = set(&ini)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
output.Errorln(err)
|
||||
os.Exit(EXIT_ACTION_ERR)
|
||||
}
|
||||
|
||||
if ArgOutput == "-" {
|
||||
output.Println(ini.Full())
|
||||
os.Exit(EXIT_SUCCESS)
|
||||
} else if ArgOutput != "" {
|
||||
ArgFile = ArgOutput
|
||||
}
|
||||
|
||||
if ArgAdd || ArgSet || ArgDel {
|
||||
if ArgInplace || ArgOutput != "" {
|
||||
err = iniWriteInplace(ArgFile, &ini)
|
||||
} else {
|
||||
err = iniWrite(ArgFile, &ini)
|
||||
}
|
||||
if err != nil {
|
||||
output.Errorln(err)
|
||||
os.Exit(EXIT_FILE_WRITE_ERR)
|
||||
}
|
||||
}
|
||||
|
||||
os.Exit(EXIT_SUCCESS)
|
||||
}
|
82
output/output.go
Normal file
82
output/output.go
Normal file
@ -0,0 +1,82 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
endOfLine string = "\n"
|
||||
devNull *log.Logger = log.New(ioutil.Discard, "", 0)
|
||||
stdout *log.Logger = log.New(os.Stdout, "", 0)
|
||||
stderr *log.Logger = log.New(os.Stderr, "", 0)
|
||||
verbose *log.Logger = devNull
|
||||
)
|
||||
|
||||
func SetVerbose(enabled bool) {
|
||||
if enabled {
|
||||
verbose = stderr
|
||||
} else {
|
||||
verbose = devNull
|
||||
}
|
||||
}
|
||||
|
||||
func SetEndOfLineNative() {
|
||||
switch os := runtime.GOOS; os {
|
||||
case "windows":
|
||||
setEndOfLineWindows()
|
||||
default:
|
||||
setEndOfLineUnix()
|
||||
}
|
||||
}
|
||||
|
||||
func EOL() string {
|
||||
return endOfLine
|
||||
}
|
||||
|
||||
func setEndOfLineUnix() {
|
||||
endOfLine = "\n"
|
||||
}
|
||||
|
||||
func setEndOfLineWindows() {
|
||||
endOfLine = "\r\n"
|
||||
}
|
||||
|
||||
func Print(v ...interface{}) {
|
||||
stdout.Print(v...)
|
||||
}
|
||||
|
||||
func Printf(format string, v ...interface{}) {
|
||||
stdout.Printf(format, v...)
|
||||
}
|
||||
|
||||
func Println(v ...interface{}) {
|
||||
stdout.Print(fmt.Sprint(v...) + endOfLine)
|
||||
}
|
||||
|
||||
func Error(v ...interface{}) {
|
||||
stderr.Print(v...)
|
||||
}
|
||||
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
stderr.Printf(format, v...)
|
||||
}
|
||||
|
||||
func Errorln(v ...interface{}) {
|
||||
stderr.Print(fmt.Sprint(v...) + endOfLine)
|
||||
}
|
||||
|
||||
func Verbose(v ...interface{}) {
|
||||
verbose.Print(v...)
|
||||
}
|
||||
|
||||
func Verbosef(format string, v ...interface{}) {
|
||||
verbose.Printf(format, v...)
|
||||
}
|
||||
|
||||
func Verboseln(v ...interface{}) {
|
||||
verbose.Print(fmt.Sprint(v...) + endOfLine)
|
||||
}
|
182
reader.go
Normal file
182
reader.go
Normal file
@ -0,0 +1,182 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"multini/output"
|
||||
"multini/types"
|
||||
)
|
||||
|
||||
var (
|
||||
// Ng - Named Group
|
||||
NgPrefix string = `prefix`
|
||||
NgPostifx string = `postfix`
|
||||
NgSection string = `section`
|
||||
NgKey string = `key`
|
||||
NgKeyPostfix string = `key_postfix`
|
||||
NgValue string = `value`
|
||||
NgValuePrefix string = `value_prefix`
|
||||
NgValuePostfix string = `value_postfix`
|
||||
NgComment string = `comment`
|
||||
NgCommentPrefix string = `comment_prefix`
|
||||
|
||||
RxBodyPrefix string = `(?P<` + NgPrefix + `>\s+)?`
|
||||
RxSectionName string = `\[(?P<` + NgSection + `>.+)\]`
|
||||
RxKey string = `(?P<` + NgKey + `>(?:[^;#=]+[^\s=;#]|[^;#=]))?`
|
||||
RxKeyPostfix string = `(?P<` + NgKeyPostfix + `>\s+)?`
|
||||
RxValuePrefix string = `(?P<` + NgValuePrefix + `>\s+)?`
|
||||
RxValue string = `(?P<` + NgValue + `>(?:[^;#]+[^\s;#]|[^;#]))?`
|
||||
RxValuePostfix string = `(?P<` + NgValuePostfix + `>\s+)?`
|
||||
RxKeyVal string = RxKey + RxKeyPostfix + `=` + RxValuePrefix + RxValue + RxValuePostfix
|
||||
RxBody string = `(?:` + RxSectionName + `|` + RxKeyVal + `)?`
|
||||
RxBodyPostfix string = `(?P<` + NgPostifx + `>\s+)?`
|
||||
RxCommentPrefix string = `(?P<` + NgCommentPrefix + `>[#;]\s*)`
|
||||
RxCommentText string = `(?P<` + NgComment + `>.+)?`
|
||||
RxComment string = `(?:` + RxCommentPrefix + RxCommentText + `)?`
|
||||
Rx string = RxBodyPrefix + RxBody + RxBodyPostfix + RxComment
|
||||
RxCompiled *regexp.Regexp = regexp.MustCompile(Rx)
|
||||
)
|
||||
|
||||
func rxParse(rx *regexp.Regexp, str string) map[string]string {
|
||||
match := rx.FindStringSubmatch(str)
|
||||
result := make(map[string]string)
|
||||
for i, name := range rx.SubexpNames() {
|
||||
if i != 0 && name != "" && i <= len(match) {
|
||||
result[name] = match[i]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func debugMap(el map[string]string) string {
|
||||
var dbgMap strings.Builder
|
||||
for key, val := range el {
|
||||
dbgMap.WriteString(" " + key + ": \"" + val + "\"" + output.EOL())
|
||||
}
|
||||
return dbgMap.String()
|
||||
}
|
||||
|
||||
func appendLine(ini *types.Ini, line string) error {
|
||||
elements := rxParse(RxCompiled, line)
|
||||
switch {
|
||||
case elements[NgSection] != "":
|
||||
var newSection types.Section
|
||||
newSection.Name = elements[NgSection]
|
||||
newSection.Prefix = elements[NgPrefix]
|
||||
newSection.Postfix = elements[NgPostifx]
|
||||
newSection.Comment.Prefix = elements[NgCommentPrefix]
|
||||
newSection.Comment.Value = elements[NgComment]
|
||||
if newSection.Line() == line {
|
||||
ini.Sections = append(ini.Sections, &newSection)
|
||||
return nil
|
||||
} else {
|
||||
output.Verboseln("Got:", newSection.Line())
|
||||
var newTrash types.Trash = types.Trash{Value: line}
|
||||
ini.Sections[len(ini.Sections)-1].(*types.Section).Lines = append(ini.Sections[len(ini.Sections)-1].(*types.Section).Lines, &newTrash)
|
||||
}
|
||||
case elements[NgKey] != "":
|
||||
var newKeyValue types.KeyValue
|
||||
newKeyValue.Key = elements[NgKey]
|
||||
newKeyValue.PostfixKey = elements[NgKeyPostfix]
|
||||
newKeyValue.PrefixKey = elements[NgPrefix]
|
||||
newKeyValue.Value = elements[NgValue]
|
||||
newKeyValue.PrefixValue = elements[NgValuePrefix]
|
||||
newKeyValue.PostfixValue = elements[NgValuePostfix]
|
||||
newKeyValue.Comment.Value = elements[NgComment]
|
||||
newKeyValue.Comment.Prefix = elements[NgCommentPrefix]
|
||||
if newKeyValue.Line() == line {
|
||||
ini.Sections[len(ini.Sections)-1].(*types.Section).Lines = append(ini.Sections[len(ini.Sections)-1].(*types.Section).Lines, &newKeyValue)
|
||||
return nil
|
||||
} else {
|
||||
output.Verboseln("Got:", newKeyValue.Line())
|
||||
var newTrash types.Trash = types.Trash{Value: line}
|
||||
ini.Sections[len(ini.Sections)-1].(*types.Section).Lines = append(ini.Sections[len(ini.Sections)-1].(*types.Section).Lines, &newTrash)
|
||||
}
|
||||
case elements[NgComment] != "":
|
||||
var newComment types.Comment
|
||||
newComment.Prefix = elements[NgPrefix] + elements[NgCommentPrefix]
|
||||
newComment.Value = elements[NgComment]
|
||||
if newComment.Line() == line {
|
||||
ini.Sections[len(ini.Sections)-1].(*types.Section).Lines = append(ini.Sections[len(ini.Sections)-1].(*types.Section).Lines, &newComment)
|
||||
return nil
|
||||
} else {
|
||||
output.Verboseln("Got:", newComment.Line())
|
||||
var newTrash types.Trash = types.Trash{Value: line}
|
||||
ini.Sections[len(ini.Sections)-1].(*types.Section).Lines = append(ini.Sections[len(ini.Sections)-1].(*types.Section).Lines, &newTrash)
|
||||
}
|
||||
case elements[NgPrefix] != "" || line == "":
|
||||
var newEmptyLine types.EmptyLine
|
||||
newEmptyLine.Prefix = elements[NgPrefix]
|
||||
if newEmptyLine.Line() == line {
|
||||
ini.Sections[len(ini.Sections)-1].(*types.Section).Lines = append(ini.Sections[len(ini.Sections)-1].(*types.Section).Lines, &newEmptyLine)
|
||||
return nil
|
||||
} else {
|
||||
output.Verboseln("Got:", newEmptyLine.Line())
|
||||
var newTrash types.Trash = types.Trash{Value: line}
|
||||
ini.Sections[len(ini.Sections)-1].(*types.Section).Lines = append(ini.Sections[len(ini.Sections)-1].(*types.Section).Lines, &newTrash)
|
||||
}
|
||||
default:
|
||||
var newTrash types.Trash = types.Trash{Value: line}
|
||||
ini.Sections[len(ini.Sections)-1].(*types.Section).Lines = append(ini.Sections[len(ini.Sections)-1].(*types.Section).Lines, &newTrash)
|
||||
}
|
||||
return errors.New(debugMap(elements))
|
||||
}
|
||||
|
||||
func iniRead(filename string) (types.Ini, error) {
|
||||
var (
|
||||
err error
|
||||
iniFile *os.File
|
||||
ini types.Ini
|
||||
)
|
||||
iniFile, err = os.Open(filename)
|
||||
|
||||
if err != nil {
|
||||
return ini, err
|
||||
}
|
||||
|
||||
fileScanner := bufio.NewScanner(iniFile)
|
||||
fileScanner.Split(bufio.ScanLines)
|
||||
ini.Init()
|
||||
|
||||
for i := 1; fileScanner.Scan(); i++ {
|
||||
appendLine(&ini, fileScanner.Text())
|
||||
}
|
||||
|
||||
iniFile.Close()
|
||||
return ini, nil
|
||||
}
|
||||
|
||||
func iniCheck(filename string) (bool, error) {
|
||||
var (
|
||||
err error
|
||||
iniFile *os.File
|
||||
ini types.Ini
|
||||
ok bool = true
|
||||
)
|
||||
iniFile, err = os.Open(filename)
|
||||
|
||||
if err != nil {
|
||||
return ok, err
|
||||
}
|
||||
|
||||
fileScanner := bufio.NewScanner(iniFile)
|
||||
fileScanner.Split(bufio.ScanLines)
|
||||
ini.Init()
|
||||
|
||||
for i := 1; fileScanner.Scan(); i++ {
|
||||
line := fileScanner.Text()
|
||||
err = appendLine(&ini, line)
|
||||
if err != nil {
|
||||
output.Errorln(i, ":", line)
|
||||
output.Verboseln(err)
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
|
||||
iniFile.Close()
|
||||
return ok, nil
|
||||
}
|
29
run_test.sh
Executable file
29
run_test.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEF='\e[0m'; BLD='\e[1m'; RED='\e[31m'; GRN='\e[32m'; WHT='\e[97m'
|
||||
ScriptFullname=$(readlink -e "$0")
|
||||
ScriptName=$(echo "$ScriptFullname" | awk -F '/' '{print $NF;}')
|
||||
ScriptDir=$(dirname "$ScriptFullname")
|
||||
TestDir="$ScriptDir/tests"
|
||||
Multini=$(readlink -e "$1")
|
||||
|
||||
if [[ -z "$Multini" ]]; then
|
||||
Multini="$ScriptDir/multini"
|
||||
fi
|
||||
|
||||
RetCode=0
|
||||
pushd "$TestDir" > /dev/null
|
||||
while read Test
|
||||
do
|
||||
echo -ne "${BLD}${WHT}[----]${DEF} $Test"
|
||||
Errors=$("$TestDir/$Test" "$Multini")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo -e "\r${BLD}${WHT}[${RED}FAIL${WHT}]${DEF} $Test"
|
||||
RetCode=1
|
||||
echo "$Errors"
|
||||
else
|
||||
echo -e "\r${BLD}${WHT}[${GRN} OK ${WHT}]${DEF} $Test"
|
||||
fi
|
||||
done < <(find "$TestDir" -type f -name 'test_*.sh' -printf "%f\n")
|
||||
popd > /dev/null
|
||||
exit "$RetCode"
|
27
tests/common.sh
Executable file
27
tests/common.sh
Executable file
@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
ScriptFullname=$(readlink -e "$0")
|
||||
ScriptName=$(echo "$ScriptFullname" | awk -F '/' '{print $NF;}')
|
||||
ScriptDir=$(dirname "$ScriptFullname")
|
||||
Multini="$1"
|
||||
InDir="$ScriptDir/in_ini"
|
||||
InIni="$InDir/$ScriptName.ini"
|
||||
OutDir="$ScriptDir/out_ini"
|
||||
OutIni="$OutDir/$ScriptName.ini"
|
||||
ExpectedIni="$ScriptDir/expected_ini/$ScriptName.ini"
|
||||
|
||||
if [[ ! -d "$OutDir" ]]; then
|
||||
mkdir -p "$OutDir"
|
||||
fi
|
||||
|
||||
rm -f "$OutIni"
|
||||
|
||||
function compare ()
|
||||
{
|
||||
if ! cmp -s "$OutIni" "$ExpectedIni" ; then
|
||||
diff "$OutIni" "$ExpectedIni"
|
||||
return 1
|
||||
fi
|
||||
rm -f "$OutIni"
|
||||
return 0
|
||||
}
|
20
tests/expected_ini/test_add_keyval.sh.ini
Normal file
20
tests/expected_ini/test_add_keyval.sh.ini
Normal file
@ -0,0 +1,20 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
Key3 = 3
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
20
tests/expected_ini/test_add_keyval_existing.sh.ini
Normal file
20
tests/expected_ini/test_add_keyval_existing.sh.ini
Normal file
@ -0,0 +1,20 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
Key = 4
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
20
tests/expected_ini/test_add_section.sh.ini
Normal file
20
tests/expected_ini/test_add_section.sh.ini
Normal file
@ -0,0 +1,20 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
||||
[NewSection]
|
18
tests/expected_ini/test_del_key.sh.ini
Normal file
18
tests/expected_ini/test_del_key.sh.ini
Normal file
@ -0,0 +1,18 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
16
tests/expected_ini/test_del_key_multiple.sh.ini
Normal file
16
tests/expected_ini/test_del_key_multiple.sh.ini
Normal file
@ -0,0 +1,16 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
18
tests/expected_ini/test_del_keyval.sh.ini
Normal file
18
tests/expected_ini/test_del_keyval.sh.ini
Normal file
@ -0,0 +1,18 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
17
tests/expected_ini/test_del_section.sh.ini
Normal file
17
tests/expected_ini/test_del_section.sh.ini
Normal file
@ -0,0 +1,17 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithoutNewLineBefore]
|
1
tests/expected_ini/test_get_key.sh.ini
Normal file
1
tests/expected_ini/test_get_key.sh.ini
Normal file
@ -0,0 +1 @@
|
||||
Some Value2 And Tabs!
|
3
tests/expected_ini/test_get_key_multiple.sh.ini
Normal file
3
tests/expected_ini/test_get_key_multiple.sh.ini
Normal file
@ -0,0 +1,3 @@
|
||||
1
|
||||
2
|
||||
3
|
0
tests/expected_ini/test_get_keyval.sh.ini
Normal file
0
tests/expected_ini/test_get_keyval.sh.ini
Normal file
7
tests/expected_ini/test_get_section.sh.ini
Normal file
7
tests/expected_ini/test_get_section.sh.ini
Normal file
@ -0,0 +1,7 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
5
tests/expected_ini/test_get_section_list.sh.ini
Normal file
5
tests/expected_ini/test_get_section_list.sh.ini
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
SimpleSection
|
||||
MultipleKeySection
|
||||
SectionWithIndent
|
||||
SectionWithoutNewLineBefore
|
17
tests/expected_ini/test_set_keyval.sh.ini
Normal file
17
tests/expected_ini/test_set_keyval.sh.ini
Normal file
@ -0,0 +1,17 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = onlyone
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_add_keyval.sh.ini
Normal file
19
tests/in_ini/test_add_keyval.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_add_keyval_existing.sh.ini
Normal file
19
tests/in_ini/test_add_keyval_existing.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_add_section.sh.ini
Normal file
19
tests/in_ini/test_add_section.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_del_key.sh.ini
Normal file
19
tests/in_ini/test_del_key.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_del_key_multiple.sh.ini
Normal file
19
tests/in_ini/test_del_key_multiple.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_del_keyval.sh.ini
Normal file
19
tests/in_ini/test_del_keyval.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_del_section.sh.ini
Normal file
19
tests/in_ini/test_del_section.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_get_key.sh.ini
Normal file
19
tests/in_ini/test_get_key.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_get_key_multiple.sh.ini
Normal file
19
tests/in_ini/test_get_key_multiple.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_get_keyval.sh.ini
Normal file
19
tests/in_ini/test_get_keyval.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_get_section.sh.ini
Normal file
19
tests/in_ini/test_get_section.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_get_section_list.sh.ini
Normal file
19
tests/in_ini/test_get_section_list.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
19
tests/in_ini/test_set_keyval.sh.ini
Normal file
19
tests/in_ini/test_set_keyval.sh.ini
Normal file
@ -0,0 +1,19 @@
|
||||
# comment
|
||||
; comment again
|
||||
|
||||
DefKey1 = Some Value1
|
||||
DefKey2 = Some Value2 And Tabs! # With Comment
|
||||
DefKey3=NoSpaces!
|
||||
|
||||
[SimpleSection] # Comment For Section
|
||||
Key1 = 1
|
||||
Key2 = 2
|
||||
|
||||
[MultipleKeySection]
|
||||
Key = 1
|
||||
Key = 2
|
||||
Key = 3
|
||||
|
||||
[SectionWithIndent]
|
||||
Key=Value
|
||||
[SectionWithoutNewLineBefore]
|
7
tests/test_add_keyval.sh
Executable file
7
tests/test_add_keyval.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini -o "$OutIni" --add "$InIni" SimpleSection Key3 3
|
||||
|
||||
compare
|
7
tests/test_add_keyval_existing.sh
Executable file
7
tests/test_add_keyval_existing.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini -o "$OutIni" --add "$InIni" MultipleKeySection Key 4
|
||||
|
||||
compare
|
7
tests/test_add_section.sh
Executable file
7
tests/test_add_section.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini -o "$OutIni" --add "$InIni" NewSection
|
||||
|
||||
compare
|
7
tests/test_del_key.sh
Executable file
7
tests/test_del_key.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini -o "$OutIni" --del "$InIni" SimpleSection Key1
|
||||
|
||||
compare
|
7
tests/test_del_key_multiple.sh
Executable file
7
tests/test_del_key_multiple.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini -o "$OutIni" --del "$InIni" MultipleKeySection Key
|
||||
|
||||
compare
|
7
tests/test_del_keyval.sh
Executable file
7
tests/test_del_keyval.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini -o "$OutIni" --del "$InIni" MultipleKeySection Key 2
|
||||
|
||||
compare
|
7
tests/test_del_section.sh
Executable file
7
tests/test_del_section.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini -o "$OutIni" --del "$InIni" SectionWithIndent
|
||||
|
||||
compare
|
7
tests/test_get_key.sh
Executable file
7
tests/test_get_key.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini --get "$InIni" '' DefKey2 > "$OutIni"
|
||||
|
||||
compare
|
7
tests/test_get_key_multiple.sh
Executable file
7
tests/test_get_key_multiple.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini --get "$InIni" MultipleKeySection Key > "$OutIni"
|
||||
|
||||
compare
|
7
tests/test_get_keyval.sh
Executable file
7
tests/test_get_keyval.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini --get "$InIni" MultipleKeySection Key 3 > "$OutIni"
|
||||
|
||||
compare
|
7
tests/test_get_section.sh
Executable file
7
tests/test_get_section.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini --get "$InIni" '' > "$OutIni"
|
||||
|
||||
compare
|
7
tests/test_get_section_list.sh
Executable file
7
tests/test_get_section_list.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini --get "$InIni" > "$OutIni"
|
||||
|
||||
compare
|
7
tests/test_set_keyval.sh
Executable file
7
tests/test_set_keyval.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "common.sh"
|
||||
|
||||
$Multini -o "$OutIni" --set "$InIni" MultipleKeySection Key onlyone
|
||||
|
||||
compare
|
26
types/comment.go
Normal file
26
types/comment.go
Normal file
@ -0,0 +1,26 @@
|
||||
package types
|
||||
|
||||
type Comment struct {
|
||||
Prefix string
|
||||
Value string
|
||||
}
|
||||
|
||||
func (obj *Comment) Full() string {
|
||||
return obj.Prefix + obj.Value
|
||||
}
|
||||
|
||||
func (obj *Comment) Line() string {
|
||||
return obj.Prefix + obj.Value
|
||||
}
|
||||
|
||||
func (obj *Comment) Fulln() string {
|
||||
return obj.Full() + endOfLine
|
||||
}
|
||||
|
||||
func (obj *Comment) Type() TElement {
|
||||
return TComment
|
||||
}
|
||||
|
||||
func (obj *Comment) Indent() string {
|
||||
return obj.Prefix
|
||||
}
|
50
types/common.go
Normal file
50
types/common.go
Normal file
@ -0,0 +1,50 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type TElement int
|
||||
|
||||
const (
|
||||
TDeleted TElement = 0
|
||||
TComment TElement = 1
|
||||
TEmptyLine TElement = 2
|
||||
TKeyValue TElement = 3
|
||||
TSection TElement = 4
|
||||
TTrash TElement = 5
|
||||
)
|
||||
|
||||
var (
|
||||
endOfLine string = "\n"
|
||||
existing bool = false
|
||||
)
|
||||
|
||||
func SetEndOfLineNative() {
|
||||
switch os := runtime.GOOS; os {
|
||||
case "windows":
|
||||
SetEndOfLineWindows()
|
||||
default:
|
||||
SetEndOfLineUnix()
|
||||
}
|
||||
}
|
||||
|
||||
func SetEndOfLineUnix() {
|
||||
endOfLine = "\n"
|
||||
}
|
||||
|
||||
func SetEndOfLineWindows() {
|
||||
endOfLine = "\r\n"
|
||||
}
|
||||
|
||||
func SetExistingMode(value bool) {
|
||||
existing = value
|
||||
}
|
||||
|
||||
func createIfNotExist() bool {
|
||||
return !existing
|
||||
}
|
||||
|
||||
func failIfNotExist() bool {
|
||||
return existing
|
||||
}
|
24
types/deleted.go
Normal file
24
types/deleted.go
Normal file
@ -0,0 +1,24 @@
|
||||
package types
|
||||
|
||||
type Deleted struct {
|
||||
}
|
||||
|
||||
func (obj *Deleted) Full() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (obj *Deleted) Line() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (obj *Deleted) Fulln() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (obj *Deleted) Type() TElement {
|
||||
return TDeleted
|
||||
}
|
||||
|
||||
func (obj *Deleted) Indent() string {
|
||||
return ""
|
||||
}
|
9
types/element.go
Normal file
9
types/element.go
Normal file
@ -0,0 +1,9 @@
|
||||
package types
|
||||
|
||||
type Element interface {
|
||||
Full() string
|
||||
Fulln() string
|
||||
Line() string
|
||||
Indent() string
|
||||
Type() TElement
|
||||
}
|
25
types/emptyline.go
Normal file
25
types/emptyline.go
Normal file
@ -0,0 +1,25 @@
|
||||
package types
|
||||
|
||||
type EmptyLine struct {
|
||||
Prefix string
|
||||
}
|
||||
|
||||
func (obj *EmptyLine) Full() string {
|
||||
return obj.Prefix
|
||||
}
|
||||
|
||||
func (obj *EmptyLine) Line() string {
|
||||
return obj.Prefix
|
||||
}
|
||||
|
||||
func (obj *EmptyLine) Fulln() string {
|
||||
return obj.Full() + endOfLine
|
||||
}
|
||||
|
||||
func (obj *EmptyLine) Type() TElement {
|
||||
return TEmptyLine
|
||||
}
|
||||
|
||||
func (obj *EmptyLine) Indent() string {
|
||||
return obj.Prefix
|
||||
}
|
152
types/ini.go
Normal file
152
types/ini.go
Normal file
@ -0,0 +1,152 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Ini struct {
|
||||
Sections []Element
|
||||
}
|
||||
|
||||
func (obj *Ini) Init() {
|
||||
obj.Sections = append(obj.Sections, &Section{}) // global section
|
||||
}
|
||||
|
||||
func (obj *Ini) Full() string {
|
||||
var body strings.Builder
|
||||
for _, line := range obj.Sections {
|
||||
body.WriteString(line.Fulln())
|
||||
}
|
||||
return body.String()
|
||||
}
|
||||
|
||||
func (obj *Ini) FindSection(name string) (*Section, error) {
|
||||
for i, sect := range obj.Sections {
|
||||
if sect.(*Section).Name == name {
|
||||
return obj.Sections[i].(*Section), nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("Section not found: " + name)
|
||||
}
|
||||
|
||||
func (obj *Ini) DelSection(name string) error {
|
||||
gotIt := false
|
||||
for i, sect := range obj.Sections {
|
||||
if sect.Type() == TSection &&
|
||||
sect.(*Section).Name == name {
|
||||
obj.Sections[i] = &Deleted{}
|
||||
gotIt = true
|
||||
}
|
||||
}
|
||||
if gotIt {
|
||||
return nil
|
||||
} else if failIfNotExist() {
|
||||
return errors.New("Section not found: " + name)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Ini) Get() string {
|
||||
var sectList strings.Builder
|
||||
for _, sect := range obj.Sections {
|
||||
name := sect.(*Section).Name
|
||||
if name != "" || len(sect.(*Section).Lines) > 0 {
|
||||
sectList.WriteString(name + endOfLine)
|
||||
}
|
||||
}
|
||||
return strings.TrimSuffix(sectList.String(), endOfLine)
|
||||
}
|
||||
|
||||
func (obj *Ini) GetSection(section string) (string, error) {
|
||||
sect, err := obj.FindSection(section)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return sect.Full(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Ini) GetKey(section, key string) (string, error) {
|
||||
sect, err := obj.FindSection(section)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return sect.GetKey(key)
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Ini) GetKeyVal(section, key, value string) error {
|
||||
sect, err := obj.FindSection(section)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
return sect.GetKeyVal(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Ini) AddSection(section string) *Section {
|
||||
sect, err := obj.FindSection(section)
|
||||
if err != nil {
|
||||
var newSection Section
|
||||
newSection.Name = section
|
||||
newSection.Prefix = obj.Sections[len(obj.Sections)-1].Indent()
|
||||
sect = &newSection
|
||||
obj.Sections = append(obj.Sections, sect)
|
||||
}
|
||||
return sect
|
||||
}
|
||||
|
||||
func (obj *Ini) SetSection(section string) *Section {
|
||||
return obj.AddSection(section)
|
||||
}
|
||||
|
||||
func (obj *Ini) AddKey(section, key, value string) error {
|
||||
sect, err := obj.FindSection(section)
|
||||
if err != nil {
|
||||
if createIfNotExist() {
|
||||
sect = obj.AddSection(section)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
sect.AddKey(key, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (obj *Ini) SetKey(section, key, value string) error {
|
||||
sect, err := obj.FindSection(section)
|
||||
if err != nil {
|
||||
if createIfNotExist() {
|
||||
sect = obj.AddSection(section)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return sect.SetKey(key, value)
|
||||
}
|
||||
|
||||
func (obj *Ini) DelKey(section, key string) error {
|
||||
sect, err := obj.FindSection(section)
|
||||
if err != nil {
|
||||
if failIfNotExist() {
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return sect.DelKey(key)
|
||||
}
|
||||
|
||||
func (obj *Ini) DelKeyVal(section, key, value string) error {
|
||||
sect, err := obj.FindSection(section)
|
||||
if err != nil {
|
||||
if failIfNotExist() {
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return sect.DelKeyVal(key, value)
|
||||
}
|
38
types/keyvalue.go
Normal file
38
types/keyvalue.go
Normal file
@ -0,0 +1,38 @@
|
||||
package types
|
||||
|
||||
type KeyValue struct {
|
||||
PrefixKey string
|
||||
Key string
|
||||
PostfixKey string
|
||||
PrefixValue string
|
||||
Value string
|
||||
PostfixValue string
|
||||
Comment Comment
|
||||
}
|
||||
|
||||
func (obj *KeyValue) Full() string {
|
||||
return obj.PrefixKey +
|
||||
obj.Key +
|
||||
obj.PostfixKey +
|
||||
"=" +
|
||||
obj.PrefixValue +
|
||||
obj.Value +
|
||||
obj.PostfixValue +
|
||||
obj.Comment.Full()
|
||||
}
|
||||
|
||||
func (obj *KeyValue) Line() string {
|
||||
return obj.Full()
|
||||
}
|
||||
|
||||
func (obj *KeyValue) Fulln() string {
|
||||
return obj.Full() + endOfLine
|
||||
}
|
||||
|
||||
func (obj *KeyValue) Type() TElement {
|
||||
return TKeyValue
|
||||
}
|
||||
|
||||
func (obj *KeyValue) Indent() string {
|
||||
return obj.PrefixKey
|
||||
}
|
185
types/section.go
Normal file
185
types/section.go
Normal file
@ -0,0 +1,185 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Section struct {
|
||||
Prefix string
|
||||
Name string
|
||||
Postfix string
|
||||
Comment Comment
|
||||
Lines []Element
|
||||
}
|
||||
|
||||
func (obj *Section) Headern() string {
|
||||
if obj.Name == "" {
|
||||
return ""
|
||||
} else {
|
||||
return obj.Prefix + "[" + obj.Name + "]" + obj.Postfix + obj.Comment.Full() + endOfLine
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Section) Line() string {
|
||||
return obj.Header()
|
||||
}
|
||||
|
||||
func (obj *Section) Header() string {
|
||||
return strings.TrimSuffix(obj.Headern(), endOfLine)
|
||||
}
|
||||
|
||||
func (obj *Section) Fulln() string {
|
||||
var body strings.Builder
|
||||
for _, line := range obj.Lines {
|
||||
body.WriteString(line.Fulln())
|
||||
}
|
||||
return obj.Headern() + body.String()
|
||||
}
|
||||
|
||||
func (obj *Section) Full() string {
|
||||
return strings.TrimSuffix(obj.Fulln(), endOfLine)
|
||||
}
|
||||
|
||||
func (obj *Section) Type() TElement {
|
||||
return TSection
|
||||
}
|
||||
|
||||
func (obj *Section) Indent() string {
|
||||
return obj.Prefix
|
||||
}
|
||||
|
||||
func (obj *Section) DelKey(name string) error {
|
||||
gotIt := false
|
||||
for i, keyVal := range obj.Lines {
|
||||
if keyVal.Type() == TKeyValue &&
|
||||
keyVal.(*KeyValue).Key == name {
|
||||
obj.Lines[i] = &Deleted{}
|
||||
gotIt = true
|
||||
}
|
||||
}
|
||||
if gotIt {
|
||||
return nil
|
||||
} else if failIfNotExist() {
|
||||
return errors.New("Parameter not found: " + name)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Section) DelKeyVal(name, value string) error {
|
||||
gotIt := false
|
||||
for i, keyVal := range obj.Lines {
|
||||
if keyVal.Type() == TKeyValue &&
|
||||
keyVal.(*KeyValue).Key == name &&
|
||||
keyVal.(*KeyValue).Value == value {
|
||||
obj.Lines[i] = &Deleted{}
|
||||
gotIt = true
|
||||
}
|
||||
}
|
||||
if gotIt {
|
||||
return nil
|
||||
} else if failIfNotExist() {
|
||||
return errors.New("Parameter:value pair not found: " + name + ":" + value)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Section) GetKey(name string) (string, error) {
|
||||
var err error = nil
|
||||
var result strings.Builder
|
||||
for _, keyVal := range obj.Lines {
|
||||
if keyVal.Type() == TKeyValue && keyVal.(*KeyValue).Key == name {
|
||||
result.WriteString(keyVal.(*KeyValue).Value + endOfLine)
|
||||
}
|
||||
}
|
||||
if result.String() == "" {
|
||||
err = errors.New("Parameter not found: " + name)
|
||||
}
|
||||
return strings.TrimSuffix(result.String(), endOfLine), err
|
||||
}
|
||||
|
||||
func (obj *Section) GetKeyVal(name, value string) error {
|
||||
for _, keyVal := range obj.Lines {
|
||||
if keyVal.Type() == TKeyValue &&
|
||||
keyVal.(*KeyValue).Key == name &&
|
||||
keyVal.(*KeyValue).Value == value {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("Parameter:Value not found: " + name + ":" + value)
|
||||
}
|
||||
|
||||
func (obj *Section) appendKey(name, value string) {
|
||||
var newKeyValue KeyValue
|
||||
var replaceIndex int = -1
|
||||
newKeyValue.Key = name
|
||||
newKeyValue.Value = value
|
||||
// replace first emptyline
|
||||
for i := len(obj.Lines) - 1; i >= 0; i-- {
|
||||
if obj.Lines[i].Type() == TEmptyLine {
|
||||
replaceIndex = i
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
// for right indent and tabs
|
||||
for i := len(obj.Lines) - 1; i >= 0; i-- {
|
||||
if obj.Lines[i].Type() == TKeyValue {
|
||||
template := obj.Lines[i].(*KeyValue)
|
||||
newKeyValue.PrefixKey = template.PrefixKey
|
||||
newKeyValue.PostfixKey = template.PostfixKey
|
||||
newKeyValue.PrefixValue = template.PrefixValue
|
||||
newKeyValue.PostfixValue = template.PostfixValue
|
||||
break
|
||||
}
|
||||
}
|
||||
if replaceIndex == -1 {
|
||||
obj.Lines = append(obj.Lines, &newKeyValue)
|
||||
} else {
|
||||
obj.Lines = append(obj.Lines, obj.Lines[replaceIndex])
|
||||
obj.Lines[replaceIndex] = &newKeyValue
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Section) AddKey(name, value string) {
|
||||
gotIt := false
|
||||
for i, keyVal := range obj.Lines {
|
||||
if keyVal.Type() == TKeyValue &&
|
||||
keyVal.(*KeyValue).Key == name &&
|
||||
keyVal.(*KeyValue).Value == value {
|
||||
if !gotIt {
|
||||
gotIt = true
|
||||
} else {
|
||||
obj.Lines[i] = &Deleted{}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !gotIt {
|
||||
obj.appendKey(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Section) SetKey(name, value string) error {
|
||||
gotIt := false
|
||||
for i, keyVal := range obj.Lines {
|
||||
if keyVal.Type() == TKeyValue &&
|
||||
keyVal.(*KeyValue).Key == name {
|
||||
if !gotIt {
|
||||
keyVal.(*KeyValue).Value = value
|
||||
gotIt = true
|
||||
} else {
|
||||
obj.Lines[i] = &Deleted{}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !gotIt {
|
||||
if createIfNotExist() {
|
||||
obj.appendKey(name, value)
|
||||
} else {
|
||||
return errors.New("Parameter not found: " + name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
25
types/trash.go
Normal file
25
types/trash.go
Normal file
@ -0,0 +1,25 @@
|
||||
package types
|
||||
|
||||
type Trash struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (obj *Trash) Full() string {
|
||||
return obj.Value
|
||||
}
|
||||
|
||||
func (obj *Trash) Line() string {
|
||||
return obj.Value
|
||||
}
|
||||
|
||||
func (obj *Trash) Fulln() string {
|
||||
return obj.Full() + endOfLine
|
||||
}
|
||||
|
||||
func (obj *Trash) Type() TElement {
|
||||
return TTrash
|
||||
}
|
||||
|
||||
func (obj *Trash) Indent() string {
|
||||
return ""
|
||||
}
|
46
writer.go
Normal file
46
writer.go
Normal file
@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"multini/types"
|
||||
)
|
||||
|
||||
func replaceOriginal(oldFile, newFile string) error {
|
||||
err := os.Remove(oldFile)
|
||||
if err == nil {
|
||||
err = os.Rename(newFile, oldFile)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func iniWrite(filename string, ini *types.Ini) error {
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "multini")
|
||||
if err == nil {
|
||||
datawriter := bufio.NewWriter(tmpFile)
|
||||
_, err = datawriter.WriteString(ini.Full())
|
||||
if err == nil {
|
||||
err = datawriter.Flush()
|
||||
tmpFile.Close()
|
||||
if err == nil {
|
||||
err = replaceOriginal(filename, tmpFile.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func iniWriteInplace(filename string, ini *types.Ini) error {
|
||||
targetFile, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err == nil {
|
||||
datawriter := bufio.NewWriter(targetFile)
|
||||
_, err = datawriter.WriteString(ini.Full())
|
||||
if err == nil {
|
||||
err = datawriter.Flush()
|
||||
targetFile.Close()
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user