14 November 2014
A very easy way to write a configuration file is to use a key-value syntax where values are indexed by a key. A sample configuration file could look something like this:
#### START CONFIGURATION #### # this is the goal you want to attain in L$ goal = 500 # this is the color of the overhead text color = 0.5, 1, 1 # cyan # this is a list of pay buttons displayed # when an avatar click the donation jar buttons = 10 ,100, 500, 1000 # if any of your keys or values have spaces # you can quote them like this: name = "Evan Saskit" # no worries, even if the values or keys # contain additional quotes, the configuration # reader will still work greeting = "Hello "Evan!", how are you?" ##### END CONFIGURATON ######
In this configuration file, we set certain values to keys, such as goal = 500
. Furthermore, everything after the hash sign #
is considered a comment and should not be considered.
Expanding on the notecard reader, we can write the following code that will read such a file and store the key-value data in a list where values are preceded by keys:
/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// // for notecard reading integer line = 0; // key-value data will be read into this list list tuples = []; default { state_entry() { if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { llSay(DEBUG_CHANNEL, "Sorry, could not find an inventory notecard."); return; } llGetNotecardLine("configuration", line); } dataserver(key id, string data) { if(data == EOF) state done; // invariant, length(tuples) % 2 == 0 if(data == "") jump continue; integer i = llSubStringIndex(data, "#"); if(i != -1) data = llDeleteSubString(data, i, -1); list o = llParseString2List(data, ["="], []); // get rid of starting and ending quotes string k = llDumpList2String( llParseString2List( llStringTrim( llList2String( o, 0 ), STRING_TRIM), ["\""], [] ), "\""); string v = llDumpList2String( llParseString2List( llStringTrim( llList2String( o, 1 ), STRING_TRIM), ["\""], [] ), "\""); if(k == "" || v == "") jump continue; tuples += k; tuples += v; @continue; llGetNotecardLine("configuration", ++line); } changed(integer change) { if(change & CHANGED_INVENTORY) { llResetScript(); } } } state done { state_entry() { llOwnerSay(llDumpList2String(tuples, ",")); } changed(integer change) { if(change & CHANGED_INVENTORY) { llResetScript(); } } }
After we have the data loaded into the tuples
list, we can extract the keys and values using key-value encode and key-value get:
llOwnerSay(wasKeyValueGet("color", wasKeyValueEncode(tuples)));
The first call is to wasKeyValueEncode
that flattens the list and the second call wasKeyValueGet
then extracts the value of the key color
. It is also possible to store the keys and values in a string type instead of the list type tuples
, thereby eliminating one call to wasKeyValueEncode
.
/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueEncode(list data) { list k = llList2ListStrided(data, 0, -1, 2); list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); data = []; do { data += llList2String(k, 0) + "=" + llList2String(v, 0); k = llDeleteSubList(k, 0, 0); v = llDeleteSubList(v, 0, 0); } while(llGetListLength(k) != 0); return llDumpList2String(data, "&"); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueGet(string k, string data) { if(llStringLength(data) == 0) return ""; if(llStringLength(k) == 0) return ""; list a = llParseStringKeepNulls(data, ["&", "="], []); integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]); if(i != -1) return llList2String(a, 2*i+1); return ""; } // for notecard reading integer line = 0; // key-value data will be read into this list list tuples = []; default { state_entry() { if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { llSay(DEBUG_CHANNEL, "Sorry, could not find an inventory notecard."); return; } llGetNotecardLine("configuration", line); } dataserver(key id, string data) { if(data == EOF) state done; // invariant, length(tuples) % 2 == 0 if(data == "") jump continue; integer i = llSubStringIndex(data, "#"); if(i != -1) data = llDeleteSubString(data, i, -1); list o = llParseString2List(data, ["="], []); string k = llStringTrim(llList2String(o, 0), STRING_TRIM); string v = llStringTrim(llList2String(o, 1), STRING_TRIM); if(k == "" || v == "") jump continue; tuples += k; tuples += v; @continue; llGetNotecardLine("configuration", ++line); } } state done { state_entry() { llOwnerSay(wasKeyValueGet("color", wasKeyValueEncode(tuples))); } }