parsecfg: handle streams and strings when saving or loading configuration (#5554)
This commit is contained in:
parent
4ba6f9808e
commit
3374bcb373
2 changed files with 124 additions and 79 deletions
|
|
@ -430,40 +430,46 @@ proc newConfig*(): Config =
|
||||||
## Useful when wanting to create a configuration file.
|
## Useful when wanting to create a configuration file.
|
||||||
result = newOrderedTable[string, OrderedTableRef[string, string]]()
|
result = newOrderedTable[string, OrderedTableRef[string, string]]()
|
||||||
|
|
||||||
proc loadConfig*(filename: string): Config =
|
proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config =
|
||||||
## Load the specified configuration file into a new Config instance.
|
## 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 dict = newOrderedTable[string, OrderedTableRef[string, string]]()
|
||||||
var curSection = "" ## Current section,
|
var curSection = "" ## Current section,
|
||||||
## the default value of the current section is "",
|
## the default value of the current section is "",
|
||||||
## which means that the current section is a common
|
## which means that the current section is a common
|
||||||
var p: CfgParser
|
var p: CfgParser
|
||||||
var fileStream = newFileStream(filename, fmRead)
|
open(p, stream, filename)
|
||||||
if fileStream != nil:
|
while true:
|
||||||
open(p, fileStream, filename)
|
var e = next(p)
|
||||||
while true:
|
case e.kind
|
||||||
var e = next(p)
|
of cfgEof:
|
||||||
case e.kind
|
break
|
||||||
of cfgEof:
|
of cfgSectionStart: # Only look for the first time the Section
|
||||||
break
|
curSection = e.section
|
||||||
of cfgSectionStart: # Only look for the first time the Section
|
of cfgKeyValuePair:
|
||||||
curSection = e.section
|
var t = newOrderedTable[string, string]()
|
||||||
of cfgKeyValuePair:
|
if dict.hasKey(curSection):
|
||||||
var t = newOrderedTable[string, string]()
|
t = dict[curSection]
|
||||||
if dict.hasKey(curSection):
|
t[e.key] = e.value
|
||||||
t = dict[curSection]
|
dict[curSection] = t
|
||||||
t[e.key] = e.value
|
of cfgOption:
|
||||||
dict[curSection] = t
|
var c = newOrderedTable[string, string]()
|
||||||
of cfgOption:
|
if dict.hasKey(curSection):
|
||||||
var c = newOrderedTable[string, string]()
|
c = dict[curSection]
|
||||||
if dict.hasKey(curSection):
|
c["--" & e.key] = e.value
|
||||||
c = dict[curSection]
|
dict[curSection] = c
|
||||||
c["--" & e.key] = e.value
|
of cfgError:
|
||||||
dict[curSection] = c
|
break
|
||||||
of cfgError:
|
close(p)
|
||||||
break
|
|
||||||
close(p)
|
|
||||||
result = dict
|
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 =
|
proc replace(s: string): string =
|
||||||
var d = ""
|
var d = ""
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -482,54 +488,61 @@ proc replace(s: string): string =
|
||||||
inc(i)
|
inc(i)
|
||||||
result = d
|
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) =
|
proc writeConfig*(dict: Config, filename: string) =
|
||||||
## Writes the contents of the table to the specified configuration file.
|
## Writes the contents of the table to the specified configuration file.
|
||||||
## Note: Comment statement will be ignored.
|
## Note: Comment statement will be ignored.
|
||||||
var file: File
|
let file = open(filename, fmWrite)
|
||||||
if file.open(filename, fmWrite):
|
let fileStream = newFileStream(filename)
|
||||||
try:
|
defer: fileStream.close()
|
||||||
var section, key, value, kv, segmentChar:string
|
dict.writeConfig(fileStream)
|
||||||
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()
|
|
||||||
|
|
||||||
proc getSectionValue*(dict: Config, section, key: string): string =
|
proc getSectionValue*(dict: Config, section, key: string): string =
|
||||||
## Gets the Key value of the specified Section.
|
## Gets the Key value of the specified Section.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
## Creating a configuration file.
|
||||||
var dict1=newConfig()
|
var dict1=newConfig()
|
||||||
|
|
@ -8,10 +35,11 @@ dict1.setSectionKey("Package","--threads","on")
|
||||||
dict1.setSectionKey("Author","name","lihf8515")
|
dict1.setSectionKey("Author","name","lihf8515")
|
||||||
dict1.setSectionKey("Author","qq","10214028")
|
dict1.setSectionKey("Author","qq","10214028")
|
||||||
dict1.setSectionKey("Author","email","lihaifeng@wxm.com")
|
dict1.setSectionKey("Author","email","lihaifeng@wxm.com")
|
||||||
dict1.writeConfig("config.ini")
|
var ss = newStringStream()
|
||||||
|
dict1.writeConfig(ss)
|
||||||
|
|
||||||
## Reading a configuration file.
|
## Reading a configuration file.
|
||||||
var dict2 = loadConfig("config.ini")
|
var dict2 = loadConfig(newStringStream(ss.data))
|
||||||
var charset = dict2.getSectionValue("","charset")
|
var charset = dict2.getSectionValue("","charset")
|
||||||
var threads = dict2.getSectionValue("Package","--threads")
|
var threads = dict2.getSectionValue("Package","--threads")
|
||||||
var pname = dict2.getSectionValue("Package","name")
|
var pname = dict2.getSectionValue("Package","name")
|
||||||
|
|
@ -25,13 +53,17 @@ echo name
|
||||||
echo qq
|
echo qq
|
||||||
echo email
|
echo email
|
||||||
|
|
||||||
|
echo "==="
|
||||||
|
|
||||||
## Modifying a configuration file.
|
## Modifying a configuration file.
|
||||||
var dict3 = loadConfig("config.ini")
|
var dict3 = loadConfig(newStringStream(ss.data))
|
||||||
dict3.setSectionKey("Author","name","lhf")
|
dict3.setSectionKey("Author","name","lhf")
|
||||||
dict3.writeConfig("config.ini")
|
write(stdout, $dict3)
|
||||||
|
|
||||||
|
echo "==="
|
||||||
|
|
||||||
## Deleting a section key in a configuration file.
|
## Deleting a section key in a configuration file.
|
||||||
var dict4 = loadConfig("config.ini")
|
var dict4 = loadConfig(newStringStream(ss.data))
|
||||||
dict4.delSectionKey("Author","email")
|
dict4.delSectionKey("Author","email")
|
||||||
dict4.writeConfig("config.ini")
|
write(stdout, $dict4)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue