parsecfg: handle streams and strings when saving or loading configuration (#5554)

This commit is contained in:
Anatoly Galiulin
2017-04-06 13:10:08 +07:00
committed by Andreas Rumpf
parent 4ba6f9808e
commit 3374bcb373
2 changed files with 124 additions and 79 deletions

View File

@@ -430,40 +430,46 @@ proc newConfig*(): Config =
## Useful when wanting to create a configuration file.
result = newOrderedTable[string, OrderedTableRef[string, string]]()
proc loadConfig*(filename: string): Config =
## Load the specified configuration file into a new Config instance.
proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config =
## Load the specified configuration from stream into a new Config instance.
## `filename` parameter is only used for nicer error messages.
var dict = newOrderedTable[string, OrderedTableRef[string, string]]()
var curSection = "" ## Current section,
## the default value of the current section is "",
## which means that the current section is a common
var p: CfgParser
var fileStream = newFileStream(filename, fmRead)
if fileStream != nil:
open(p, fileStream, filename)
while true:
var e = next(p)
case e.kind
of cfgEof:
break
of cfgSectionStart: # Only look for the first time the Section
curSection = e.section
of cfgKeyValuePair:
var t = newOrderedTable[string, string]()
if dict.hasKey(curSection):
t = dict[curSection]
t[e.key] = e.value
dict[curSection] = t
of cfgOption:
var c = newOrderedTable[string, string]()
if dict.hasKey(curSection):
c = dict[curSection]
c["--" & e.key] = e.value
dict[curSection] = c
of cfgError:
break
close(p)
open(p, stream, filename)
while true:
var e = next(p)
case e.kind
of cfgEof:
break
of cfgSectionStart: # Only look for the first time the Section
curSection = e.section
of cfgKeyValuePair:
var t = newOrderedTable[string, string]()
if dict.hasKey(curSection):
t = dict[curSection]
t[e.key] = e.value
dict[curSection] = t
of cfgOption:
var c = newOrderedTable[string, string]()
if dict.hasKey(curSection):
c = dict[curSection]
c["--" & e.key] = e.value
dict[curSection] = c
of cfgError:
break
close(p)
result = dict
proc loadConfig*(filename: string): Config =
## Load the specified configuration file into a new Config instance.
let file = open(filename, fmRead)
let fileStream = newFileStream(file)
defer: fileStream.close()
result = fileStream.loadConfig(filename)
proc replace(s: string): string =
var d = ""
var i = 0
@@ -482,54 +488,61 @@ proc replace(s: string): string =
inc(i)
result = d
proc writeConfig*(dict: Config, stream: Stream) =
## Writes the contents of the table to the specified stream
##
## **Note:** Comment statement will be ignored.
for section, sectionData in dict.pairs():
if section != "": ## Not general section
if not allCharsInSet(section, SymChars): ## Non system character
stream.writeLine("[\"" & section & "\"]")
else:
stream.writeLine("[" & section & "]")
for key, value in sectionData.pairs():
var kv, segmentChar: string
if key.len > 1 and key[0] == '-' and key[1] == '-': ## If it is a command key
segmentChar = ":"
if not allCharsInSet(key[2..key.len()-1], SymChars):
kv.add("--\"")
kv.add(key[2..key.len()-1])
kv.add("\"")
else:
kv = key
else:
segmentChar = "="
kv = key
if value != "": ## If the key is not empty
if not allCharsInSet(value, SymChars):
if find(value, '"') == -1:
kv.add(segmentChar)
kv.add("\"")
kv.add(replace(value))
kv.add("\"")
else:
kv.add(segmentChar)
kv.add("\"\"\"")
kv.add(replace(value))
kv.add("\"\"\"")
else:
kv.add(segmentChar)
kv.add(value)
stream.writeLine(kv)
proc `$`*(dict: Config): string =
## Writes the contents of the table to string.
## Note: Comment statement will be ignored.
let stream = newStringStream()
defer: stream.close()
dict.writeConfig(stream)
result = stream.data
proc writeConfig*(dict: Config, filename: string) =
## Writes the contents of the table to the specified configuration file.
## Note: Comment statement will be ignored.
var file: File
if file.open(filename, fmWrite):
try:
var section, key, value, kv, segmentChar:string
for pair in dict.pairs():
section = pair[0]
if section != "": ## Not general section
if not allCharsInSet(section, SymChars): ## Non system character
file.writeLine("[\"" & section & "\"]")
else:
file.writeLine("[" & section & "]")
for pair2 in pair[1].pairs():
key = pair2[0]
value = pair2[1]
if key[0] == '-' and key[1] == '-': ## If it is a command key
segmentChar = ":"
if not allCharsInSet(key[2..key.len()-1], SymChars):
kv.add("--\"")
kv.add(key[2..key.len()-1])
kv.add("\"")
else:
kv = key
else:
segmentChar = "="
kv = key
if value != "": ## If the key is not empty
if not allCharsInSet(value, SymChars):
if find(value, '"') == -1:
kv.add(segmentChar)
kv.add("\"")
kv.add(replace(value))
kv.add("\"")
else:
kv.add(segmentChar)
kv.add("\"\"\"")
kv.add(replace(value))
kv.add("\"\"\"")
else:
kv.add(segmentChar)
kv.add(value)
file.writeLine(kv)
except:
raise
finally:
file.close()
let file = open(filename, fmWrite)
let fileStream = newFileStream(filename)
defer: fileStream.close()
dict.writeConfig(fileStream)
proc getSectionValue*(dict: Config, section, key: string): string =
## Gets the Key value of the specified Section.

View File

@@ -1,4 +1,31 @@
import parsecfg
discard """
output: '''
utf-8
on
hello
lihf8515
10214028
lihaifeng@wxm.com
===
charset=utf-8
[Package]
name=hello
--threads:on
[Author]
name=lhf
qq=10214028
email="lihaifeng@wxm.com"
===
charset=utf-8
[Package]
name=hello
--threads:on
[Author]
name=lihf8515
qq=10214028
'''
"""
import parsecfg, streams
## Creating a configuration file.
var dict1=newConfig()
@@ -8,10 +35,11 @@ dict1.setSectionKey("Package","--threads","on")
dict1.setSectionKey("Author","name","lihf8515")
dict1.setSectionKey("Author","qq","10214028")
dict1.setSectionKey("Author","email","lihaifeng@wxm.com")
dict1.writeConfig("config.ini")
var ss = newStringStream()
dict1.writeConfig(ss)
## Reading a configuration file.
var dict2 = loadConfig("config.ini")
var dict2 = loadConfig(newStringStream(ss.data))
var charset = dict2.getSectionValue("","charset")
var threads = dict2.getSectionValue("Package","--threads")
var pname = dict2.getSectionValue("Package","name")
@@ -25,13 +53,17 @@ echo name
echo qq
echo email
echo "==="
## Modifying a configuration file.
var dict3 = loadConfig("config.ini")
var dict3 = loadConfig(newStringStream(ss.data))
dict3.setSectionKey("Author","name","lhf")
dict3.writeConfig("config.ini")
write(stdout, $dict3)
echo "==="
## Deleting a section key in a configuration file.
var dict4 = loadConfig("config.ini")
var dict4 = loadConfig(newStringStream(ss.data))
dict4.delSectionKey("Author","email")
dict4.writeConfig("config.ini")
write(stdout, $dict4)