Task: Update a configuration file




Go: package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"unicode"
)


type line struct {
	kind     lineKind
	option   string
	value    string
	disabled bool
}


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}
	}
	
	semi := false
	for len(fields[0]) > 0 && fields[0][0] == ';' {
		semi = true
		fields[0] = fields[0][1:]
	}
	
	if fields[0] == "" {
		fields = fields[1:]
	}
	switch len(fields) {
	case 0:
		
		
		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}
}


type Config struct {
	options map[string]int		
	lines   []line
}



func (c *Config) index(option string) int {
	if i, ok := c.options[option]; ok {
		return i
	}
	return -1
}



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)
	}
}


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 {
				
				s = s[:len(s)-1]
			}
			c.addLine(parseLine(s))
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
	}
	return c, nil
}



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,
	})
}



func (c *Config) Enable(option string, enabled bool) {
	if i := c.index(option); i >= 0 {
		c.lines[i].disabled = !enabled
	}
}


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)
}





VB: Set objFSO = CreateObject("Scripting.FileSystemObject")


Set objParamLookup = CreateObject("Scripting.Dictionary")
With objParamLookup
	.Add "FAVOURITEFRUIT", "banana"
	.Add "NEEDSPEELING", ""
	.Add "SEEDSREMOVED", ""
	.Add "NUMBEROFBANANAS", "1024"
	.Add "NUMBEROFSTRAWBERRIES", "62000"
End With 


Set objInFile = objFSO.OpenTextFile(objFSO.GetParentFolderName(WScript.ScriptFullName) &_
	"\IN_config.txt",1)

Output = ""	
Isnumberofstrawberries = False
With objInFile
	Do Until .AtEndOfStream
		line = .ReadLine
		If Left(line,1) = "#" Or line = "" Then
			Output = Output & line & vbCrLf
		ElseIf Left(line,1) = " " And InStr(line,"#") Then
			Output = Output & Mid(line,InStr(1,line,"#"),1000) & vbCrLf
		ElseIf Replace(Replace(line,";","")," ","") <> "" Then
			If InStr(1,line,"FAVOURITEFRUIT",1) Then
				Output = Output & "FAVOURITEFRUIT" & " " & objParamLookup.Item("FAVOURITEFRUIT") & vbCrLf
			ElseIf InStr(1,line,"NEEDSPEELING",1) Then
				Output = Output & "; " & "NEEDSPEELING" & vbCrLf
			ElseIf InStr(1,line,"SEEDSREMOVED",1) Then
				Output = Output & "SEEDSREMOVED" & vbCrLf
			ElseIf InStr(1,line,"NUMBEROFBANANAS",1) Then
				Output = Output & "NUMBEROFBANANAS" & " " & objParamLookup.Item("NUMBEROFBANANAS") & vbCrLf
			ElseIf InStr(1,line,"NUMBEROFSTRAWBERRIES",1) Then
				Output = Output & "NUMBEROFSTRAWBERRIES" & " " & objParamLookup.Item("NUMBEROFSTRAWBERRIES") & vbCrLf
				Isnumberofstrawberries = True
			End If
		End If
	Loop
	If Isnumberofstrawberries = False Then
		Output = Output & "NUMBEROFSTRAWBERRIES" & " " & objParamLookup.Item("NUMBEROFSTRAWBERRIES") & vbCrLf
		Isnumberofstrawberries = True
	End If
	.Close
End With
	

Set objOutFile = objFSO.OpenTextFile(objFSO.GetParentFolderName(WScript.ScriptFullName) &_
	"\OUT_config.txt",2,True)
With objOutFile
	.Write Output
	.Close
End With

Set objFSO = Nothing
Set objParamLookup = Nothing