Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
|
|
@ -0,0 +1,204 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// line represents a single line in the configuration file.
|
||||
type line struct {
|
||||
kind lineKind
|
||||
option string
|
||||
value string
|
||||
disabled bool
|
||||
}
|
||||
|
||||
// lineKind represents the different kinds of configuration line.
|
||||
type lineKind int
|
||||
|
||||
const (
|
||||
_ lineKind = iota
|
||||
ignore
|
||||
parseError
|
||||
comment
|
||||
blank
|
||||
value
|
||||
)
|
||||
|
||||
func (l line) String() string {
|
||||
switch l.kind {
|
||||
case ignore, parseError, comment, blank:
|
||||
return l.value
|
||||
case value:
|
||||
s := l.option
|
||||
if l.disabled {
|
||||
s = "; " + s
|
||||
}
|
||||
if l.value != "" {
|
||||
s += " " + l.value
|
||||
}
|
||||
return s
|
||||
}
|
||||
panic("unexpected line kind")
|
||||
}
|
||||
|
||||
func removeDross(s string) string {
|
||||
return strings.Map(func(r rune) rune {
|
||||
if r < 32 || r > 0x7f || unicode.IsControl(r) {
|
||||
return -1
|
||||
}
|
||||
return r
|
||||
}, s)
|
||||
}
|
||||
|
||||
func parseLine(s string) line {
|
||||
if s == "" {
|
||||
return line{kind: blank}
|
||||
}
|
||||
if s[0] == '#' {
|
||||
return line{kind: comment, value: s}
|
||||
}
|
||||
s = removeDross(s)
|
||||
fields := strings.Fields(s)
|
||||
if len(fields) == 0 {
|
||||
return line{kind: blank}
|
||||
}
|
||||
// Strip leading semicolons (but record that we found them)
|
||||
semi := false
|
||||
for len(fields[0]) > 0 && fields[0][0] == ';' {
|
||||
semi = true
|
||||
fields[0] = fields[0][1:]
|
||||
}
|
||||
// Lose the first field if it was all semicolons
|
||||
if fields[0] == "" {
|
||||
fields = fields[1:]
|
||||
}
|
||||
switch len(fields) {
|
||||
case 0:
|
||||
// This can only happen if the line starts
|
||||
// with a semicolon but has no other information
|
||||
return line{kind: ignore}
|
||||
case 1:
|
||||
return line{
|
||||
kind: value,
|
||||
option: strings.ToUpper(fields[0]),
|
||||
disabled: semi,
|
||||
}
|
||||
case 2:
|
||||
return line{
|
||||
kind: value,
|
||||
option: strings.ToUpper(fields[0]),
|
||||
value: fields[1],
|
||||
disabled: semi,
|
||||
}
|
||||
}
|
||||
return line{kind: parseError, value: s}
|
||||
}
|
||||
|
||||
// Config represents a "standard" configuration file.
|
||||
type Config struct {
|
||||
options map[string]int // index of each option in lines.
|
||||
lines []line
|
||||
}
|
||||
|
||||
// index returns the index of the given option in
|
||||
// c.lines, or -1 if not found.
|
||||
func (c *Config) index(option string) int {
|
||||
if i, ok := c.options[option]; ok {
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// addLine adds a line to the config, ignoring
|
||||
// duplicate options and "ignore" lines.
|
||||
func (c *Config) addLine(l line) {
|
||||
switch l.kind {
|
||||
case ignore:
|
||||
return
|
||||
case value:
|
||||
if c.index(l.option) >= 0 {
|
||||
return
|
||||
}
|
||||
c.options[l.option] = len(c.lines)
|
||||
c.lines = append(c.lines, l)
|
||||
default:
|
||||
c.lines = append(c.lines, l)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadConfig reads a configuration file from path and returns it.
|
||||
func ReadConfig(path string) (*Config, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
r := bufio.NewReader(f)
|
||||
c := &Config{options: make(map[string]int)}
|
||||
for {
|
||||
s, err := r.ReadString('\n')
|
||||
if s != "" {
|
||||
if err == nil {
|
||||
// strip newline unless we encountered an error without finding one.
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
c.addLine(parseLine(s))
|
||||
}
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Set sets an option to a value, adding the option if necessary. If
|
||||
// the option was previously disabled, it will be enabled.
|
||||
func (c *Config) Set(option string, val string) {
|
||||
if i := c.index(option); i >= 0 {
|
||||
line := &c.lines[i]
|
||||
line.disabled = false
|
||||
line.value = val
|
||||
return
|
||||
}
|
||||
c.addLine(line{
|
||||
kind: value,
|
||||
option: option,
|
||||
value: val,
|
||||
})
|
||||
}
|
||||
|
||||
// Enable sets the enabled status of an option. It is
|
||||
// ignored if the option does not already exist.
|
||||
func (c *Config) Enable(option string, enabled bool) {
|
||||
if i := c.index(option); i >= 0 {
|
||||
c.lines[i].disabled = !enabled
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes the configuration file to the writer.
|
||||
func (c *Config) Write(w io.Writer) {
|
||||
for _, line := range c.lines {
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
c, err := ReadConfig("/tmp/cfg")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
c.Enable("NEEDSPEELING", false)
|
||||
c.Set("SEEDSREMOVED", "")
|
||||
c.Set("NUMBEROFBANANAS", "1024")
|
||||
c.Set("NUMBEROFSTRAWBERRIES", "62000")
|
||||
c.Write(os.Stdout)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue