-
Notifications
You must be signed in to change notification settings - Fork 0
/
ini.go
136 lines (123 loc) · 3.39 KB
/
ini.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
Copyright © 2019, 2024 M.Watermann, 10247 Berlin, Germany
All rights reserved
EMail : <[email protected]>
*/
package ini
import (
"io/fs"
"os"
"path/filepath"
"strings"
)
//lint:file-ignore ST1017 - I prefer Yoda conditions
// `NewIni()` reads the given `aFilename` returning the data structure read
// from that INI file and a possible error condition.
//
// If `aFilename` is empty, the method returns an empty `TSectionList`
// and a `fs.ErrNotExist`.
//
// This function reads one line at a time of the INI file skipping both
// empty lines and comments (identified by '#' or ';' at line start).
//
// Parameters:
//
// `aFilename` The name of the INI file to read.
//
// Returns:
//
// *TSectionList: The list of sections of the INI file.
// error: A possible error condition.
func NewIni(aFilename string) (*TSectionList, error) {
if aFilename = strings.TrimSpace(aFilename); "" == aFilename {
return NewSectionList(), fs.ErrNotExist
}
result := NewSectionList().SetFilename(aFilename)
return result.load()
} // New()
// `ReadIniData()` returns the config values read from INI file(s).
//
// The steps here are:
// (1) read the local `./.aName.ini`,
// (2) read the global `/etc/aName.ini`,
// (3) read the user-local `~/.aName.ini`,
// (4) read the user-local `~/.config/aName.ini`,
// (5) read the `-ini` commandline argument.
//
// This utility function returns the `Default` section of the INI files.
// It is intended for applications that only use the single default section
// for its configuration values.
//
// Example:
//
// iniData := ReadIniData("myApp")
// fmt.Println(iniData.AsString("", "myKey"))
//
// The function returns a pointer to the 'Default' section
// of the first INI file that contains it.
//
// Parameters:
//
// `aName` The application's name used as the INI file name
//
// (without `.ini` extension).
//
// Returns:
//
// *TSection: The default section of the INI file.
// *TSectionList: The list of sections of the INI file.
func ReadIniData(aName string) (*TSection, *TSectionList) {
var (
confDir string
err error
ini1, ini2 *TSectionList
)
// (1) ./
fName, _ := filepath.Abs(`./` + aName + `.ini`)
if ini1, err = NewIni(fName); nil == err {
ini1.AddSectionKey("", `iniFile`, fName)
}
// (2) /etc/
fName = `/etc/` + aName + `.ini`
if ini2, err = NewIni(fName); nil == err {
ini1.Merge(ini2)
ini1.AddSectionKey("", `iniFile`, fName)
}
// (3) ~user/
fName, err = os.UserHomeDir()
if (nil == err) && (0 < len(fName)) {
fName, _ = filepath.Abs(filepath.Join(fName, `.`+aName+`.ini`))
if ini2, err = NewIni(fName); nil == err {
ini1.Merge(ini2)
ini1.AddSectionKey("", `iniFile`, fName)
}
}
// (4) ~/.config/
if confDir, err = os.UserConfigDir(); nil == err {
fName, _ = filepath.Abs(filepath.Join(confDir, aName+`.ini`))
if ini2, err = NewIni(fName); nil == err {
ini1.Merge(ini2)
ini1.AddSectionKey("", `iniFile`, fName)
}
}
// (5) cmdline
aLen := len(os.Args)
for i := 1; i < aLen; i++ {
if `-ini` == os.Args[i] {
//XXX Note that this works only if `-ini` and
// filename are two separate arguments. It will
// fail if it's given in the form `-ini=filename`.
i++
if i < aLen {
fName, _ = filepath.Abs(os.Args[i])
if ini2, err = NewIni(fName); nil == err {
ini1.Merge(ini2)
ini1.AddSectionKey("", `iniFile`, fName)
}
}
break
}
}
return ini1.GetSection(""), ini1
} // ReadIniData()
/* _EoF_ */