KEVN ("Key Equals Value, Newline") is a basic, INI-like file parser for Lua (LÖVE).
; Comment
key=value
website=https://www.example.com/
[group_id]
foo=bar
bar=foo
INI files are similar to a Lua hash table with one level of nesting. They're comprised of key-value pairs (foo=bar
) that belong to groups ([config]
). The groups and keys are unordered. All groups have unique names, and all keys have unique names within their group.
That's the gist. There is no official INI specification that I'm aware of, and you can find any number of implementations with differing features. If you are evaluating KEVN for use in your project, be aware that it is case-sensitive and strict about whitespace.
INI files are suitable for storage and retrieval of basic configuration, and they can also be used for basic metadata. While not pretty, they are human-readable, and can be modified with a simple text editor.
KEVN is not well suited for ordered sequences of data, or text that spans multiple lines.
While KEVN imposes no limit on the size of lines, very long stretches of text without a break can be difficult for users to read.
For more complex use cases, consider json.lua by rxi or serpent by Paul Kulchenko
See the kevn_test repo for testing. (It will eventually have some LÖVE-specific demos once I get around to writing them.)
-
Empty lines, lines containing only whitespace, and lines beginning with a semicolon (comments) are ignored.
-
Line feeds (
\n
) are used to split lines, and therefore cannot be part of any group ID, key or value.- On Windows, when loading files from disk, you may need to convert
\r\n
pairs to just\n
. LÖVE'sfilesystem
module does this automatically.
- On Windows, when loading files from disk, you may need to convert
-
With one exception, as far as the parser is concerned, all other whitespace is significant.
foo = bar
will result in the key "foo " and the value " bar". The group declaration[con fig ]
becomes "con fig ".- The one exception is that trailing whitespace after the
]
in a group declaration is ignored:[config]
- The one exception is that trailing whitespace after the
-
Keys cannot contain
=
, and they cannot have;
or[
as their first character. -
Keys and values can be empty. A single
=
is equivalent to a key of""
with a value of""
. -
Group IDs cannot contain
]
. -
Any duplicate groups or duplicate keys within the same group are treated as an error.
-
The group
[]
is automatically created for any key-value pairs which appear before the first group declaration. It can be declared explicitly at the top of the file to ensure that the empty-string group is always created. Declaring it after this implicit creation is treated as an error. -
By default, all groups, keys and values are returned from the parser as strings. You can pass in modifier callbacks to perform additional processing and validity checks on group IDs and key+value pairs. (See API: Modifiers for more on that.) Or you can edit the table after it has been returned.
Without modifiers, the resulting output table looks something like this:
local tbl = {
[""] = { --; (The default / global group)
this = "here", --this=here
}, --
player = { --[player]
name = "Drernrern", --name=Drernrern
health = "100", --health=100
level = "1", --level=1
}, --
another_group = { --[another_group]
et = "cetera.", --et=cetera.
},
}
Converts a KEVN string to a Lua table.
local tbl = kevn.str2Table(str, fn_group, fn_key)
-
str
: The KEVN string to parse. -
fn_group
: An optional group ID modifier function. (See API: Modifiers) -
fn_key
: An optional key+value modifier function. (See API: Modifiers)
Returns: A Lua table, or false and error string if parsing failed.
Converts a table to a KEVN string. The output is unordered, comments are not supported, and all group names, keys and values must be strings. For more control over output, see API: Writer Functions.
local str = kevn.table2Str(tbl)
tbl
The table to convert.
Returns: A string based on the table.
Use these functions to construct an INI string in pieces.
-- Create an empty table
local tmp = {}
-- Write some lines
kevn.appendGroupID(tmp, "the_group")
kevn.appendKey(tmp, "hello", "world")
-- Finalize
local str = table.concat(tmp, "\n")
-- Output:
--[[
[the_group]
hello=world
--]]
Note that it's possible to create an invalid KEVN string by writing duplicate group or key names. You can reload the string with kevn.str2Table
to test it.
Appends a group ID to the writing table.
kevn.appendGroupID(temp, group_id)
-
temp
The WIP table of strings. -
group_id
The group ID to write. Cannot contain\n
or]
.
Appends a key-value pair to the writing table.
kevn.appendKey(temp, key, value)
-
temp
The WIP table of strings. -
key
(string) The key to write. Cannot contain\n
or=
, and cannot have;
as its first character. -
value
(string) The value to write. Cannot contain\n
.
Appends a comment to the writing table. Line feeds (\n
) are permitted, and will split the string into multiple comment lines.
kevn.appendComment(temp, comment)
-
temp
The WIP table of strings. -
comment
(string) The comment to write.
Appends one or more empty lines for spacing.
kevn.appendEmpty(temp, n)
-
temp
: The WIP table of strings. -
n
(Number) The number of empty lines to append. Default: 1
Modifiers are optional callbacks that allow you to verify and mess with group IDs, keys and values while parsing. Use cases include:
-
Implementation of type conversion or escape sequences, like converting the string
"true"
to booleantrue
. -
Checking that a key+value pair is valid in context.
You can skip this entirely and check the returned table after the fact, but using modifiers does allow including the line number of an offending section in your error messages.
Modifier callback for group IDs.
local result, new_group_id = fn_group(tbl, group_id)
-
tbl
: The work-in-progress table. (Be careful about modifying this during parsing.) -
group_id
: The parsed group ID.
Returns: 1) true or false/nil, indicating success or failure, 2) A replacement group ID with no type restrictions, or an error string in the event of failure.
Modifier callback for key+value pairs.
local result, new_key, new_value = fn_key(tbl, group_id, key, value)
-
tbl
: The work-in-progress table. (Be careful about modifying this during parsing.) -
group_id
: The group ID this key belongs to. Note that it may have been modified (changed type) byfn_group
. -
key
: The parsed key. -
value
: The parsed value.
Returns: 1) true or false/nil, indicating success or failure, 2) a replacement key with no type restrictions, or an error string in the event of failure, and 3) a replacement value with no type restrictions.
Copyright (c) 2023 RBTS
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.