2020-04-25 23:42:14 +00:00
|
|
|
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
|
2020-04-27 11:35:10 +00:00
|
|
|
ArgReverse bool
|
|
|
|
ArgQuiet bool
|
2020-04-25 23:42:14 +00:00
|
|
|
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:")
|
2020-04-27 11:35:10 +00:00
|
|
|
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.")
|
2020-04-25 23:42:14 +00:00
|
|
|
output.Println("")
|
|
|
|
output.Println("Options:")
|
|
|
|
output.Println(" -e, --existing For --set and --del, fail if item is missing.")
|
2020-04-27 11:35:10 +00:00
|
|
|
output.Println(" -r, --reverse For --add, adds an item to the top of the section")
|
2020-04-25 23:42:14 +00:00
|
|
|
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")
|
2020-04-27 11:35:10 +00:00
|
|
|
output.Println(" -q, --quiet Suppress all normal output")
|
2020-04-25 23:42:14 +00:00
|
|
|
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, "")
|
2020-04-27 11:35:10 +00:00
|
|
|
gnuflag.BoolVar(&ArgInplace, "inplace", false, "")
|
|
|
|
gnuflag.BoolVar(&ArgInplace, "i", false, "")
|
2020-04-25 23:42:14 +00:00
|
|
|
gnuflag.BoolVar(&ArgUnix, "unix", false, "")
|
|
|
|
gnuflag.BoolVar(&ArgUnix, "u", false, "")
|
|
|
|
gnuflag.BoolVar(&ArgWindows, "windows", false, "")
|
|
|
|
gnuflag.BoolVar(&ArgWindows, "w", false, "")
|
2020-04-27 11:35:10 +00:00
|
|
|
gnuflag.BoolVar(&ArgReverse, "reverse", false, "")
|
|
|
|
gnuflag.BoolVar(&ArgReverse, "r", false, "")
|
2020-04-25 23:42:14 +00:00
|
|
|
gnuflag.BoolVar(&ArgExisting, "existing", false, "")
|
|
|
|
gnuflag.BoolVar(&ArgExisting, "e", false, "")
|
2020-04-27 11:35:10 +00:00
|
|
|
gnuflag.BoolVar(&ArgQuiet, "quiet", false, "")
|
|
|
|
gnuflag.BoolVar(&ArgQuiet, "q", false, "")
|
2020-04-25 23:42:14 +00:00
|
|
|
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)
|
2020-04-27 11:35:10 +00:00
|
|
|
output.SetQuiet(ArgQuiet)
|
2020-04-25 23:42:14 +00:00
|
|
|
|
|
|
|
// 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")
|
|
|
|
}
|
|
|
|
}
|