summary refs log tree commit diff stats
path: root/lib/pure/parsecfg.nim
diff options
context:
space:
mode:
authorflywind <43030857+xflywind@users.noreply.github.com>2020-12-06 16:50:46 +0800
committerGitHub <noreply@github.com>2020-12-06 09:50:46 +0100
commit48d7c40553f0769c22b4b47f8079dd96c3e23323 (patch)
treef31daea6eae62c74e0545aad8b6cafbedd9576de /lib/pure/parsecfg.nim
parent1aaa67fc18879bd2aa8ae8f5e7dc763f826c73b6 (diff)
downloadNim-48d7c40553f0769c22b4b47f8079dd96c3e23323.tar.gz
fix #16206 (#16207)
* better docs and tests
* a bit better only clean trailing whitespace
Diffstat (limited to 'lib/pure/parsecfg.nim')
-rw-r--r--lib/pure/parsecfg.nim70
1 files changed, 69 insertions, 1 deletions
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 9b140a809..c87010122 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -107,6 +107,70 @@
 ##     var dict = loadConfig("config.ini")
 ##     dict.delSectionKey("Author","email")
 ##     dict.writeConfig("config.ini")
+## 
+## Supported INI File structure
+## ----------------------------
+## The examples below are supported:
+##
+
+# taken from https://docs.python.org/3/library/configparser.html#supported-ini-file-structure
+runnableExamples:
+  import streams
+
+  var dict = loadConfig(newStringStream("""[Simple Values]
+    key=value
+    spaces in keys=allowed
+    spaces in values=allowed as well
+    spaces around the delimiter = obviously
+    you can also use : to delimit keys from values
+    [All Values Are Strings]
+    values like this: 19990429
+    or this: 3.14159265359
+    are they treated as numbers : no
+    integers floats and booleans are held as: strings
+    can use the API to get converted values directly: true
+    [No Values]
+    key_without_value
+    # empty string value is not allowed =
+    [ Seletion A   ]
+    space around section name will be ignored
+    [You can use comments]
+    # like this
+    ; or this
+    # By default only in an empty line.
+    # Inline comments can be harmful because they prevent users
+    # from using the delimiting characters as parts of values.
+    # That being said, this can be customized.
+        [Sections Can Be Indented]
+            can_values_be_as_well = True
+            does_that_mean_anything_special = False
+            purpose = formatting for readability
+            # Did I mention we can indent comments, too?
+    """)
+  )
+
+  let section1 = "Simple Values"
+  doAssert dict.getSectionValue(section1, "key") == "value"
+  doAssert dict.getSectionValue(section1, "spaces in keys") == "allowed"
+  doAssert dict.getSectionValue(section1, "spaces in values") == "allowed as well"
+  doAssert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously"
+  doAssert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values"
+
+  let section2 = "All Values Are Strings"
+  doAssert dict.getSectionValue(section2, "values like this") == "19990429"
+  doAssert dict.getSectionValue(section2, "or this") == "3.14159265359"
+  doAssert dict.getSectionValue(section2, "are they treated as numbers") == "no"
+  doAssert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings"
+  doAssert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true"
+
+  let section3 = "Seletion A"
+  doAssert dict.getSectionValue(section3, 
+    "space around section name will be ignored", "not an empty value") == ""
+
+  let section4 = "Sections Can Be Indented"
+  doAssert dict.getSectionValue(section4, "can_values_be_as_well") == "True"
+  doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False"
+  doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability"
 
 import
   strutils, lexbase, streams, tables
@@ -151,7 +215,7 @@ type
 # implementation
 
 const
-  SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.', '/', '\\', '-'}
+  SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', ' ', '\x80'..'\xFF', '.', '/', '\\', '-'}
 
 proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.}
 
@@ -306,6 +370,10 @@ proc getSymbol(c: var CfgParser, tok: var Token) =
     add(tok.literal, c.buf[pos])
     inc(pos)
     if not (c.buf[pos] in SymChars): break
+
+  while tok.literal.len > 0 and tok.literal[^1] == ' ':
+    tok.literal.setLen(tok.literal.len - 1)
+
   c.bufpos = pos
   tok.kind = tkSymbol