summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-05-26 10:51:10 +0200
committerAndreas Rumpf <rumpf_a@web.de>2016-05-26 10:51:10 +0200
commit301d39b88202f5042198caf26a11d7a6257d5bd9 (patch)
tree2165d47924f6636c42f24a562c693bbee9b2cf8b
parentd11a1a68fd0d1e8d0688da2a5da56e6c215dcb3b (diff)
parent42bd3fd9532876672ae56e05c48e857ab43a3d3e (diff)
downloadNim-301d39b88202f5042198caf26a11d7a6257d5bd9.tar.gz
Merge pull request #4130 from lihf8515/devel
Update parsecfg.nim
-rw-r--r--lib/pure/parsecfg.nim200
-rw-r--r--tests/stdlib/tparscfg.nim58
2 files changed, 233 insertions, 25 deletions
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 9bcac0a50..bf19d5540 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -22,10 +22,71 @@
 ##
 ## .. code-block:: nim
 ##     :file: examples/parsecfgex.nim
-
+## 
+## Examples
+## --------
+##
+## This is an example of a configuration file.
+## 
+## .. include:: config.ini
+## 
+##     charset = "utf-8"
+##     [Package]
+##     name = "hello"
+##     --threads:on
+##     [Author]
+##     name = "lihf8515"
+##     qq = "10214028"
+##     email = "lihaifeng@wxm.com"
+## 
+## Creating a configuration file.
+## ==============================
+## .. code-block:: nim
+## 
+##     import parsecfg
+##     var dict=newConfig()
+##     dict.setSectionKey("","charset","utf-8")
+##     dict.setSectionKey("Package","name","hello")
+##     dict.setSectionKey("Package","--threads","on")
+##     dict.setSectionKey("Author","name","lihf8515")
+##     dict.setSectionKey("Author","qq","10214028")
+##     dict.setSectionKey("Author","email","lihaifeng@wxm.com")
+##     dict.writeConfig("config.ini")
+## 
+## Reading a configuration file.
+## =============================
+## .. code-block:: nim
+##
+##     import parsecfg
+##     var dict = loadConfig("config.ini")
+##     var charset = dict.getSectionValue("","charset")
+##     var threads = dict.getSectionValue("Package","--threads")
+##     var pname = dict.getSectionValue("Package","name")
+##     var name = dict.getSectionValue("Author","name")
+##     var qq = dict.getSectionValue("Author","qq")
+##     var email = dict.getSectionValue("Author","email")
+##     echo pname & "\n" & name & "\n" & qq & "\n" & email
+## 
+## Modifying a configuration file.
+## ===============================
+## .. code-block:: nim
+## 
+##     import parsecfg
+##     var dict = loadConfig("config.ini")
+##     dict.setSectionKey("Author","name","lhf")
+##     dict.writeConfig("config.ini")
+##
+## Deleting a section key in a configuration file.
+## ===============================================
+## .. code-block:: nim
+## 
+##     import parsecfg
+##     var dict = loadConfig("config.ini")
+##     dict.delSectionKey("Author","email")
+##     dict.writeConfig("config.ini")
 
 import
-  hashes, strutils, lexbase, streams
+  hashes, strutils, lexbase, streams, tables
 
 include "system/inclrtl"
 
@@ -359,3 +420,138 @@ proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} =
     result.kind = cfgError
     result.msg = errorStr(c, "invalid token: " & c.tok.literal)
     rawGetTok(c, c.tok)
+
+# ---------------- Configuration file related operations ----------------
+type
+  Config* = OrderedTableRef[string, OrderedTableRef[string, string]]
+
+proc newConfig*(): Config =
+  ## Create a new configuration table.
+  ## 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.
+  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)
+  result = dict
+
+proc replace(s: string): string =
+  var d = ""
+  var i = 0
+  while i < s.len():
+    if s[i] == '\\':
+      d.add(r"\\")
+    elif s[i] == '\c' and s[i+1] == '\L':
+      d.add(r"\n")
+      inc(i)
+    elif s[i] == '\c':
+      d.add(r"\n")
+    elif s[i] == '\L':
+      d.add(r"\n")
+    else:
+      d.add(s[i])
+    inc(i)
+  result = d
+
+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):
+              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 =
+  ## Gets the Key value of the specified Section.
+  if dict.haskey(section):
+    if dict[section].hasKey(key):
+      result = dict[section][key]
+    else:
+      result = ""
+  else:
+    result = ""
+
+proc setSectionKey*(dict: var Config, section, key, value: string) =
+  ## Sets the Key value of the specified Section.
+  var t = newOrderedTable[string, string]()
+  if dict.hasKey(section):
+    t = dict[section]
+  t[key] = value
+  dict[section] = t
+
+proc delSection*(dict: var Config, section: string) =
+  ## Deletes the specified section and all of its sub keys.
+  dict.del(section)
+
+proc delSectionKey*(dict: var Config, section, key: string) =
+  ## Delete the key of the specified section.
+  if dict.haskey(section):
+    if dict[section].hasKey(key):
+      if dict[section].len() == 1:
+        dict.del(section)
+      else:
+        dict[section].del(key)
diff --git a/tests/stdlib/tparscfg.nim b/tests/stdlib/tparscfg.nim
index 4c11ccf61..7022d071b 100644
--- a/tests/stdlib/tparscfg.nim
+++ b/tests/stdlib/tparscfg.nim
@@ -1,25 +1,37 @@
+import parsecfg
 
-import
-  os, parsecfg, strutils, streams
+## Creating a configuration file.
+var dict1=newConfig()
+dict1.setSectionKey("","charset","utf-8")
+dict1.setSectionKey("Package","name","hello")
+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")
+
+## Reading a configuration file.
+var dict2 = loadConfig("config.ini")
+var charset = dict2.getSectionValue("","charset")
+var threads = dict2.getSectionValue("Package","--threads")
+var pname = dict2.getSectionValue("Package","name")
+var name = dict2.getSectionValue("Author","name")
+var qq = dict2.getSectionValue("Author","qq")
+var email = dict2.getSectionValue("Author","email")
+echo charset
+echo threads
+echo pname
+echo name
+echo qq
+echo email
+
+## Modifying a configuration file.
+var dict3 = loadConfig("config.ini")
+dict3.setSectionKey("Author","name","lhf")
+dict3.writeConfig("config.ini")
+
+## Deleting a section key in a configuration file.
+var dict4 = loadConfig("config.ini")
+dict4.delSectionKey("Author","email")
+dict4.writeConfig("config.ini")
 
-var f = newFileStream(paramStr(1), fmRead)
-if f != nil:
-  var p: TCfgParser
-  open(p, f, paramStr(1))
-  while true:
-    var e = next(p)
-    case e.kind
-    of cfgEof:
-      echo("EOF!")
-      break
-    of cfgSectionStart:   ## a ``[section]`` has been parsed
-      echo("new section: " & e.section)
-    of cfgKeyValuePair:
-      echo("key-value-pair: " & e.key & ": " & e.value)
-    of cfgOption:
-      echo("command: " & e.key & ": " & e.value)
-    of cfgError:
-      echo(e.msg)
-  close(p)
-else:
-  echo("cannot open: " & paramStr(1))