summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/cld/cld-luafunctions.tex
diff options
context:
space:
mode:
Diffstat (limited to 'doc/context/sources/general/manuals/cld/cld-luafunctions.tex')
-rw-r--r--doc/context/sources/general/manuals/cld/cld-luafunctions.tex2367
1 files changed, 2367 insertions, 0 deletions
diff --git a/doc/context/sources/general/manuals/cld/cld-luafunctions.tex b/doc/context/sources/general/manuals/cld/cld-luafunctions.tex
new file mode 100644
index 000000000..b2760e05b
--- /dev/null
+++ b/doc/context/sources/general/manuals/cld/cld-luafunctions.tex
@@ -0,0 +1,2367 @@
+% language=uk
+
+% table.unnest : only used in special cases
+% table.derive : set metatable if unset
+% table.compact : remove empty subtables
+
+\environment cld-environment
+
+\startcomponent cld-luafunctions
+
+\startchapter[title=Lua Functions]
+
+\startsection[title={Introduction}]
+
+When you run \CONTEXT\ you have some libraries preloaded. If you look into the
+\LUA\ files you will find more than is discussed here, but keep in mind that what
+is not documented, might be gone or done different one day. Some extensions live
+in the same namespace as those provided by stock \LUA\ and \LUATEX, others have
+their own. There are many more functions and the more obscure (or never being
+used) ones will go away.
+
+The \LUA\ code in \CONTEXT\ is organized in quite some modules. Those with names
+like \type {l-*.lua} are rather generic and are automatically available when you
+use \type {mtxrun} to run a \LUA\ file. These are discusses in this chapter. A
+few more modules have generic properties, like some in the categories \type
+{util-*.lua}, \type {trac-*.lua}, \type {luat-*.lua}, \type {data-*.lua} and
+\type {lxml-*.lua}. They contain more specialized functions and are discussed
+elsewhere.
+
+Before we move on the the real code, let's introduce a handy helper:
+
+\starttyping
+inspect(somevar)
+\stoptyping
+
+Whenever you feel the need to see what value a variable has you can insert this
+function to get some insight. It knows how to deal with several data types.
+
+\stopsection
+
+\startsection[title={Tables}]
+
+\startsummary[title={[lua] concat}]
+
+These functions come with \LUA\ itself and are discussed in detail in the \LUA\
+reference manual so we stick to some examples. The \type {concat} function
+stitches table entries in an indexed table into one string, with an optional
+separator in between. If can also handle a slice of the table
+
+\starttyping
+local str = table.concat(t)
+local str = table.concat(t,separator)
+local str = table.concat(t,separator,first)
+local str = table.concat(t,separator,first,last)
+\stoptyping
+
+Only strings and numbers can be concatenated.
+
+\ShowLuaExampleThree {table} {concat} {{"a","b","c","d","e"}}
+\ShowLuaExampleThree {table} {concat} {{"a","b","c","d","e"},"+"}
+\ShowLuaExampleThree {table} {concat} {{"a","b","c","d","e"},"+",2,3}
+
+\stopsummary
+
+\startsummary[title={[lua] insert remove}]
+
+You can use \type {insert} and \type {remove} for adding or replacing entries in
+an indexed table.
+
+\starttyping
+table.insert(t,value,position)
+value = table.remove(t,position)
+\stoptyping
+
+The position is optional and defaults to the last entry in the table. For
+instance a stack is built this way:
+
+\starttyping
+table.insert(stack,"top")
+local top = table.remove(stack)
+\stoptyping
+
+Beware, the \type {insert} function returns nothing. You can provide an
+additional position:
+
+\starttyping
+table.insert(list,"injected in slot 2",2)
+local thiswastwo = table.remove(list,2)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={[lua] unpack}]
+
+You can access entries in an indexed table as follows:
+
+\starttyping
+local a, b, c = t[1], t[2], t[3]
+\stoptyping
+
+but this does the same:
+
+\starttyping
+local a, b, c = table.unpack(t)
+\stoptyping
+
+This is less efficient but there are situations where \type {unpack}
+comes in handy.
+
+\stopsummary
+
+\startsummary[title={[lua] sort}]
+
+Sorting is done with \type {sort}, a function that does not return a value but
+operates on the given table.
+
+\starttyping
+table.sort(t)
+table.sort(t,comparefunction)
+\stoptyping
+
+The compare function has to return a consistent equivalent of \type {true} or
+\type {false}. For sorting more complex data structures there is a specialized
+sort module available.
+
+\ShowLuaExampleFour {table} {sort} {{"a","b","c"}} {}
+\ShowLuaExampleFour {table} {sort} {{"a","b","c"}} {,function(x,y) return x > y end}
+\ShowLuaExampleFour {table} {sort} {{"a","b","c"}} {,function(x,y) return x < y end}
+
+\stopsummary
+
+\startsummary[title={sorted}]
+
+The built|-|in \type {sort} function does not return a value but sometimes it can be
+if the (sorted) table is returned. This is why we have:
+
+\starttyping
+local a = table.sorted(b)
+\stoptyping
+
+\stopsummary
+
+% table.strip
+
+\startsummary[title={keys sortedkeys sortedhashkeys sortedhash}]
+
+The \type {keys} function returns an indexed list of keys. The order is undefined
+as it depends on how the table was constructed. A sorted list is provided by
+\type {sortedkeys}. This function is rather liberal with respect to the keys. If
+the keys are strings you can use the faster alternative \type {sortedhashkeys}.
+
+\starttyping
+local s = table.keys (t)
+local s = table.sortedkeys (t)
+local s = table.sortedhashkeys (t)
+\stoptyping
+
+Because a sorted list is often processed there is also an iterator:
+
+\starttyping
+for key, value in table.sortedhash(t) do
+ print(key,value)
+end
+\stoptyping
+
+There is also a synonym \type {sortedpairs} which sometimes looks more natural
+when used alongside the \type {pairs} and \type {ipairs} iterators.
+
+\ShowLuaExampleTwo {table} {keys} {{ [1] = 2, c = 3, [true] = 1 }}
+\ShowLuaExampleTwo {table} {sortedkeys} {{ [1] = 2, c = 3, [true] = 1 }}
+\ShowLuaExampleTwo {table} {sortedhashkeys} {{ a = 2, c = 3, b = 1 }}
+
+\stopsummary
+
+\startsummary[title={serialize print tohandle tofile}]
+
+The \type {serialize} function converts a table into a verbose representation.
+The \type {print} function does the same but prints the result to the console
+which is handy for tracing. The \type {tofile} function writes the table to a
+file, using reasonable chunks so that less memory is used. The fourth variant
+\type {tohandle} takes a handle so that you can do whatever you like with the
+result.
+
+\starttyping
+table.serialize (root, name, reduce, noquotes, hexify)
+table.print (root, name, reduce, noquotes, hexify)
+table.tofile (filename, root, name, reduce, noquotes, hexify)
+table.tohandle (handle, root, name, reduce, noquotes, hexify)
+\stoptyping
+
+The serialization can be controlled in several ways. Often only the first two
+options makes sense:
+
+\ShowLuaExampleOne {table} {serialize} {{ a = 2 }}
+\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, "name"}
+\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, true}
+\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, false}
+\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, "return"}
+\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, 12}
+
+\ShowLuaExampleOne {table} {serialize} {{ a = 2, [3] = "b", [true] = "6" }, nil, true}
+\ShowLuaExampleOne {table} {serialize} {{ a = 2, [3] = "b", [true] = "6" }, nil, true, true}
+\ShowLuaExampleOne {table} {serialize} {{ a = 2, [3] = "b", [true] = "6" }, nil, true, true, true}
+
+In \CONTEXT\ there is also a \type {tocontext} function that typesets the table
+verbose. This is handy for manuals and tracing.
+
+\stopsummary
+
+\startsummary[title={identical are_equal}]
+
+These two function compare two tables that have a similar structure. The \type
+{identical} variant operates on a hash while \type {are_equal} assumes an indexed
+table.
+
+\starttyping
+local b = table.identical (one, two)
+local b = table.are_equal (one, two)
+\stoptyping
+
+\ShowLuaExampleThree {table} {identical} {{ a = { x = 2 } }, { a = { x = 3 } }}
+\ShowLuaExampleThree {table} {identical} {{ a = { x = 2 } }, { a = { x = 2 } }}
+
+\ShowLuaExampleThree {table} {are_equal} {{ a = { x = 2 } }, { a = { x = 3 } }}
+\ShowLuaExampleThree {table} {are_equal} {{ a = { x = 2 } }, { a = { x = 2 } }}
+
+\ShowLuaExampleThree {table} {identical} {{ "one", "two" }, { "one", "two" }}
+\ShowLuaExampleThree {table} {identical} {{ "one", "two" }, { "two", "one" }}
+
+\ShowLuaExampleThree {table} {are_equal} {{ "one", "two" }, { "one", "two" }}
+\ShowLuaExampleThree {table} {are_equal} {{ "one", "two" }, { "two", "one" }}
+
+\stopsummary
+
+\startsummary[title={tohash fromhash swapped swaphash reversed reverse mirrored}]
+
+We use \type {tohash} quite a lot in \CONTEXT. It converts a list into a hash so
+that we can easily check if (a string) is in a given set. The \type {fromhash}
+function does the opposite: it creates a list of keys from a hashed table where
+each value that is not \type {false} or \type {nil} is present.
+
+\starttyping
+local hashed = table.tohash (indexed)
+local indexed = table.fromhash(hashed)
+\stoptyping
+
+The function \type {swapped} turns keys into values vise versa while the \type
+{reversed} and \type {reverse} reverses the values in an indexed table. The last
+one reverses the table itself (in|-|place).
+
+\starttyping
+local swapped = table.swapped (indexedtable)
+local reversed = table.reversed (indexedtable)
+local reverse = table.reverse (indexedtable)
+local mirrored = table.mirrored (hashedtable)
+\stoptyping
+
+\ShowLuaExampleTwo {table} {tohash} {{ "a", "b", "c" }}
+\ShowLuaExampleTwo {table} {fromhash} {{ a = true, b = false, c = true }}
+\ShowLuaExampleTwo {table} {swapped} {{ "a", "b", "c" }}
+\ShowLuaExampleTwo {table} {reversed} {{ "a", "b", "c" }}
+\ShowLuaExampleTwo {table} {reverse} {{ 1, 2, 3, 4 }}
+\ShowLuaExampleTwo {table} {mirrored} {{ a = "x", b = "y", c = "z" }}
+
+\stopsummary
+
+\startsummary[title={append prepend}]
+
+These two functions operate on a pair of indexed tables. The first table gets
+appended or prepended by the second. The first table is returned as well.
+
+\starttyping
+table.append (one, two)
+table.prepend(one, two)
+\stoptyping
+
+The functions are similar to loops using \type {insert}.
+
+\ShowLuaExampleTwo {table} {append} {{ "a", "b", "c" }, { "d", "e" }}
+\ShowLuaExampleTwo {table} {prepend} {{ "a", "b", "c" }, { "d", "e" }}
+
+\stopsummary
+
+\startsummary[title={merge merged imerge imerged}]
+
+You can merge multiple hashes with \type {merge} and indexed tables with \type
+{imerge}. The first table is the target and is returned.
+
+\starttyping
+table.merge (one, two, ...)
+table.imerge (one, two, ...)
+\stoptyping
+
+The variants ending with a \type {d} merge the given list of tables and return
+the result leaving the first argument untouched.
+
+\starttyping
+local merged = table.merged (one, two, ...)
+local merged = table.imerged (one, two, ...)
+\stoptyping
+
+\ShowLuaExampleTwo {table} {merge} {{ a = 1, b = 2, c = 3 }, { d = 1 }, { a = 0 }}
+\ShowLuaExampleTwo {table} {imerge} {{ "a", "b", "c" }, { "d", "e" }, { "f", "g" }}
+
+% \ShowLuaExampleTwo {table} {merged} {{ a = 1, b = 2, c = 3 }, { d = 1 }, { a = 0 }}
+% \ShowLuaExampleTwo {table} {imerged} {{ "a", "b", "c" }, { "d", "e" }, { "f", "g" }}
+
+\stopsummary
+
+\startsummary[title={copy fastcopy}]
+
+When copying a table we need to make a real and deep copy. The \type {copy}
+function is an adapted version from the \LUA\ wiki. The \type {fastopy} is faster
+because it does not check for circular references and does not share tables when
+possible. In practice using the fast variant is okay.
+
+\starttyping
+local copy = table.copy (t)
+local copy = table.fastcopy(t)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={flattened}]
+
+A nested table can be unnested using \type {flattened}. Normally you will only
+use this function if the content is somewhat predictable. Often using one of the
+merge functions does a similar job.
+
+\starttyping
+local flattened = table.flatten(t)
+\stoptyping
+
+\ShowLuaExampleTwo {table} {flattened} {{ a = 1, b = 2, { c = 3 }, d = 4}}
+\ShowLuaExampleTwo {table} {flattened} {{ 1, 2, { 3, { 4 } }, 5}}
+\ShowLuaExampleTwo {table} {flattened} {{ 1, 2, { 3, { 4 } }, 5}, 1}
+\ShowLuaExampleTwo {table} {flattened} {{ a = 1, b = 2, { c = 3 }, d = 4}}
+\ShowLuaExampleTwo {table} {flattened} {{ 1, 2, { 3, { c = 4 } }, 5}}
+\ShowLuaExampleTwo {table} {flattened} {{ 1, 2, { 3, { c = 4 } }, 5}, 1}
+
+\stopsummary
+
+\startsummary[title={loweredkeys}]
+
+The name says it all: this function returns a new table with the keys being lower
+case. This is handy in cases where the keys have a change to be inconsistent, as
+can be the case when users input keys and values in less controlled ways.
+
+\starttyping
+local normalized = table.loweredkeys { a = "a", A = "b", b = "c" }
+\stoptyping
+
+\ShowLuaExampleTwo {table} {loweredkeys} {{ a = 1, b = 2, C = 3}}
+
+\stopsummary
+
+\startsummary[title={contains}]
+
+This function works with indexed tables. Watch out, when you look for a match,
+the number \type {1} is not the same as string \type {"1"}. The function returns
+the index or \type {false}.
+
+\starttyping
+if table.contains(t, 5 ) then ... else ... end
+if table.contains(t,"5") then ... else ... end
+\stoptyping
+
+\ShowLuaExampleThree {table} {contains} {{ "a", 2, true, "1"}, 1}
+\ShowLuaExampleThree {table} {contains} {{ "a", 2, true, "1"}, "1"}
+
+\stopsummary
+
+\startsummary[title={unique}]
+
+When a table (can) contain duplicate entries you can get rid of them by using the
+\type {unique} helper:
+
+\starttyping
+local t = table.unique { 1, 2, 3, 4, 3, 2, 5, 6 }
+\stoptyping
+
+\ShowLuaExampleTwo {table} {unique} { { "a", "b", "c", "a", "d" } }
+
+\stopsummary
+
+\startsummary[title={count}]
+
+The name speaks for itself: this function counts the number of entries in the
+given table. For an indexed table \type {#t} is faster.
+
+\starttyping
+local n = table.count(t)
+\stoptyping
+
+\ShowLuaExampleThree {table} {count} {{ 1, 2, [4] = 4, a = "a" }}
+
+\stopsummary
+
+\startsummary[title={sequenced}]
+
+Normally, when you trace a table, printing the serialized version is quite
+convenient. However, when it concerns a simple table, a more compact variant is:
+
+\starttyping
+print(table.sequenced(t, separator))
+\stoptyping
+
+% beware: by default sequences has | as separator
+
+\ShowLuaExampleThree {table} {sequenced} {{ 1, 2, 3, 4}}
+\ShowLuaExampleThree {table} {sequenced} {{ 1, 2, [4] = 4, a = "a" }, ", "}
+
+\stopsummary
+
+\stopsection
+
+\startsection[title=Math]
+
+In addition to the built-in math function we provide: \type {round}, \type {odd},
+\type {even}, \type {div}, \type {mod}, \type {sind}, \type {cosd} and
+\type {tand}.
+
+At the \TEX\ end we have a helper \type {luaexpr} that you can use to do
+calculations:
+
+\startbuffer
+ \luaexpr{1 + 2.3 * 4.5 + math.pi} = \cldcontext{1 + 2.3 * 4.5 + math.pi}
+\stopbuffer
+
+\typebuffer
+
+Both calls return the same result, but the first one is normally faster than the
+\type {context} command which has quite some overhead.
+
+\blank \getbuffer \blank
+
+The \type {\luaexpr} command can also better deal with for instance conditions,
+where it returns \type {true} or \type {false}, while \type {\cldcontext} would
+interpret the boolean value as a special signal.
+
+\stopsection
+
+\startsection[title=Booleans]
+
+\startsummary[title={tonumber}]
+
+This function returns the number one or zero. You will seldom need this function.
+
+\starttyping
+local state = boolean.tonumber(str)
+\stoptyping
+
+\ShowLuaExampleThree {boolean} {tonumber} {true}
+
+\stopsummary
+
+\startsummary[title={toboolean}]
+
+When dealing with configuration files or tables a bit flexibility in setting a
+state makes sense, if only because in some cases it's better to say \type {yes}
+than \type {true}.
+
+\starttyping
+local b = toboolean(str)
+local b = toboolean(str,tolerant)
+\stoptyping
+
+When the second argument is true, the strings \type {true}, \type {yes}, \type
+{on}, \type {1}, \type {t} and the number \type {1} all turn into \type {true}.
+Otherwise only \type {true} is honoured. This function is also defined in the
+global namespace.
+
+\ShowLuaExampleThree {string} {toboolean} {"true"}
+\ShowLuaExampleThree {string} {toboolean} {"yes"}
+\ShowLuaExampleThree {string} {toboolean} {"yes",true}
+
+\stopsummary
+
+\startsummary[title={is_boolean}]
+
+This function is somewhat similar to the previous one. It interprets the strings
+\type {true}, \type {yes}, \type {on} and \type {t} as \type {true} and
+\type{false}, \type {no}, \type {off} and \type {f} as \type {false}. Otherwise
+\type {nil} is returned, unless a default value is given, in which case that is
+returned.
+
+\starttyping
+if is_boolean(str) then ... end
+if is_boolean(str,default) then ... end
+\stoptyping
+
+\ShowLuaExampleThree {string} {is_boolean} {"true"}
+\ShowLuaExampleThree {string} {is_boolean} {"off"}
+\ShowLuaExampleThree {string} {is_boolean} {"crap",true}
+
+\stopsummary
+
+\stopsection
+
+\startsection[title=Strings]
+
+\LUA\ strings are simply sequences of bytes. Of course in some places special
+treatment takes place. For instance \type {\n} expands to one or more characters
+representing a newline, depending on the operating system, but normally, as long
+as you manipulate strings in the perspective of \LUATEX, you don't need to worry
+about such issues too much. As \LUATEX\ is a \UTF-8 engine, strings normally are
+in that encoding but again, it does not matter much as \LUA\ is quite agnostic
+about the content of strings: it does not care about three characters reflecting
+one \UNICODE\ character or not. This means that when you use for instance the
+functions discussed here, or use libraries like \type {lpeg} behave as you
+expect.
+
+Versions later than 0.75 are likely to have some basic \UNICODE\ support on board
+but we can easily adapt to that. At least till \LUATEX\ version 0.75 we provided
+the \type {slunicode} library but users cannot assume that that will be present for
+ever. If you want to mess around with \UTF\ string, use the \type {utf} library
+instead as that is the one we provide in \MKIV. It presents the stable interface to
+whatever \LUA\ itself provides and|/|or what \LUATEX\ offers and|/|or what
+is there because \MKIV\ implements it.
+
+\startsummary[title={[lua] byte char}]
+
+As long as we're dealing with \ASCII\ characters we can use these two functions to
+go from numbers to characters and vise versa.
+
+\ShowLuaExampleSeven {string} {byte} {"luatex"}
+\ShowLuaExampleSeven {string} {byte} {"luatex",1,3}
+\ShowLuaExampleSeven {string} {byte} {"luatex",-3,-1}
+
+\ShowLuaExampleSeven {string} {char} {65}
+\ShowLuaExampleSeven {string} {char} {65,66,67}
+
+\stopsummary
+
+\startsummary[title={[lua] sub}]
+
+You cannot directly access a character in a string but you can take any slice you
+want using \type {sub}. You need to provide a start position and negative values
+will count backwards from the end.
+
+\starttyping
+local slice = string.sub(str,first,last)
+\stoptyping
+
+\ShowLuaExampleThree {string} {sub} {"abcdef",2}
+\ShowLuaExampleThree {string} {sub} {"abcdef",2,3}
+\ShowLuaExampleThree {string} {sub} {"abcdef",-3,-2}
+
+\stopsummary
+
+\startsummary[title={[lua] gsub}]
+
+There are two ways of analyzing the content of a string. The more modern and
+flexible approach is to use \type {lpeg}. The other one uses some functions in
+the \type {string} namespace that accept so called patterns for matching. While
+\type {lpeg} is more powerfull than regular expressions, the pattern matching is
+less powerfull but sometimes faster and also easier to specify. In many cases it
+can do the job quite well.
+
+\starttyping
+local new, count = string.gsub(old,pattern,replacement)
+\stoptyping
+
+The replacement can be a function. Often you don't want the number
+of matches, and the way to avoid this is either to store the result
+in a variable:
+
+\starttyping
+local new = string.gsub(old,"lua","LUA")
+print(new)
+\stoptyping
+
+or to use parentheses to signal the interpreter that only one value
+is return.
+
+\starttyping
+print((string.gsub(old,"lua","LUA"))
+\stoptyping
+
+Patterns can be more complex so you'd better read the \LUA\ manual if you want to
+know more about them.
+
+\ShowLuaExampleThree {string} {gsub} {"abcdef","b","B"}
+\ShowLuaExampleThree {string} {gsub} {"abcdef","[bc]",string.upper}
+
+An optional fourth argument specifies how often the replacement has to happen
+
+\ShowLuaExampleThree {string} {gsub} {"textextextex","tex","abc"}
+\ShowLuaExampleThree {string} {gsub} {"textextextex","tex","abc",1}
+\ShowLuaExampleThree {string} {gsub} {"textextextex","tex","abc",2}
+
+\stopsummary
+
+\startsummary[title={[lua] find}]
+
+The \type {find} function returns the first and last position of the match:
+
+\starttyping
+local first, last = find(str,pattern)
+\stoptyping
+
+If you're only interested if there is a match at all, it's enough to know that
+there is a first position. No match returns \type {nil}. So,
+
+\starttyping
+if find("luatex","tex") then ... end
+\stoptyping
+
+works out okay. You can pass an extra argument to \type {find} that indicates the
+start position. So you can use this function to loop over all matches: just start
+again at the end of the last match.
+
+A fourth optional argument is a boolean that signals not to interpret the pattern
+but use it as|-|is.
+
+\ShowLuaExampleThree {string} {find} {"abc.def","c\letterpercent.d",1,false}
+\ShowLuaExampleThree {string} {find} {"abc.def","c\letterpercent.d",1,true}
+\ShowLuaExampleThree {string} {find} {"abc\letterpercent.def","c\letterpercent.d",1,false}
+\ShowLuaExampleThree {string} {find} {"abc\letterpercent.def","c\letterpercent.d",1,true}
+
+\stopsummary
+
+\startsummary[title={[lua] match gmatch}]
+
+With \type {match} you can split of bits and pieces of a string. The parenthesis
+indicate the captures.
+
+\starttyping
+local a, b, c, ... = string.match(str,pattern)
+\stoptyping
+
+The \type {gmatch} function is used to loop over a string, for instance the
+following code prints the elements in a comma separated list, ignoring spaces
+after commas.
+
+\starttyping
+for s in string.gmatch(str,"([^,%s])+") do
+ print(s)
+end
+\stoptyping
+
+A more detailed description can be found in the \LUA\ reference manual, so we
+only mention the special directives. Characters are grouped in classes:
+
+\starttabulate[|lT|l|]
+\HL
+\NC \letterpercent a \NC letters \NC \NR
+\NC \letterpercent l \NC lowercase letters \NC \NR
+\NC \letterpercent u \NC uppercase letters \NC \NR
+\NC \letterpercent d \NC digits \NC \NR
+\NC \letterpercent w \NC letters and digits \NC \NR
+\NC \letterpercent c \NC control characters \NC \NR
+\NC \letterpercent p \NC punctuation \NC \NR
+\NC \letterpercent x \NC hexadecimal characters \NC \NR
+\NC \letterpercent s \NC space related characters \NC \NR
+\HL
+\stoptabulate
+
+You can create sets too:
+
+\starttabulate[|lT|l|]
+\HL
+\NC [\letterpercent l\letterpercent d] \NC lowercase letters and digits \NC \NR
+\NC [^\letterpercent d\letterpercent p] \NC all characters except digits and punctuation \NC \NR
+\NC [p-z] \NC all characters in the range \type {p} upto \type {z} \NC \NR
+\NC [pqr] \NC all characters \type {p}, \type {q} and \type {r} \NC \NR
+\HL
+\stoptabulate
+
+There are some characters with special meanings:
+
+\starttabulate[|lT|l|]
+\HL
+\NC \letterhat \NC the beginning of a string \NC \NR
+\NC \letterdollar \NC end of a string \NC \NR
+\NC . \NC any character \NC \NR
+\NC * \NC zero or more of the preceding specifier, greedy \NC \NR
+\NC - \NC zero or more of the preceding specifier, least possible \NC \NR
+\NC + \NC one or more of the preceding specifier \NC \NR
+\NC ? \NC zero or one of the preceding specifier \NC \NR
+\NC ( ) \NC encapsulate capture \NC \NR
+\NC \letterpercent b \NC capture all between the following two characters \NC \NR
+\HL
+\stoptabulate
+
+You can use whatever you like to be matched:
+
+\starttabulate[|lT|l|]
+\HL
+\NC pqr \NC the sequence \type {pqr} \NC \NR
+\NC my name is (\letterpercent w) \NC the word following \type {my name is} \NC \NR
+\HL
+\stoptabulate
+
+If you want to specify such a token as it is, then you can precede it with a
+percent sign, so to get a percent, you need two in a row.
+
+\ShowLuaExampleThree {string} {match} {"before:after","^(.-):"}
+\ShowLuaExampleThree {string} {match} {"before:after","^([^:])"}
+\ShowLuaExampleThree {string} {match} {"before:after","bef(.*)ter"}
+\ShowLuaExampleThree {string} {match} {"abcdef","[b-e]+"}
+\ShowLuaExampleThree {string} {match} {"abcdef","[b-e]*"}
+\ShowLuaExampleThree {string} {match} {"abcdef","b-e+"}
+\ShowLuaExampleThree {string} {match} {"abcdef","b-e*"}
+
+\stopsummary
+
+Such patterns should not be confused with regular expressions, although to some
+extent they can do the same. If you really want to do complex matches, you should
+look into \LPEG.
+
+\startsummary[title={[lua] lower upper}]
+
+These two function spreak for themselves.
+
+\ShowLuaExampleThree {string} {lower} {"LOW"}
+\ShowLuaExampleThree {string} {upper} {"upper"}
+
+\stopsummary
+
+\startsummary[title={[lua] format}]
+
+The \type {format} function takes a template as first argument and one or more
+additional arguments depending on the format. The template is similar to the one
+used in \CCODE\ but it has some extensions.
+
+\starttyping
+local s = format(format, str, ...)
+\stoptyping
+
+The following table gives an overview of the possible format directives. The
+\type {s} is the most probably candidate and can handle numbers well as strings.
+Watch how the minus sign influences the alignment. \footnote {There can be
+differences between platforms although so far we haven't run into problems. Also,
+\LUA\ 5.2 does a bit more checking on correct arguments and \LUA\ 5.3 is more
+picky on integers.}
+
+\starttabulate[|lB|lT|lT|lT|]
+\HL
+\NC integer \NC \letterpercent i \NC 12345 \NC \cldcontext{string.format("\letterpercent i", 12345 )} \NC \NR
+\NC integer \NC \letterpercent d \NC 12345 \NC \cldcontext{string.format("\letterpercent d", 12345 )} \NC \NR
+\NC unsigned \NC \letterpercent u \NC -12345 \NC \cldcontext{string.format("\letterpercent u", 12345 )} \NC \NR
+\NC character \NC \letterpercent c \NC 123 \NC \cldcontext{string.format("\letterpercent c", 89 )} \NC \NR
+\NC hexadecimal \NC \letterpercent x \NC 123 \NC \cldcontext{string.format("\letterpercent x", 123 )} \NC \NR
+\NC \NC \letterpercent X \NC 123 \NC \cldcontext{string.format("\letterpercent X", 123 )} \NC \NR
+\NC octal \NC \letterpercent o \NC 12345 \NC \cldcontext{string.format("\letterpercent o", 12345 )} \NC \NR
+\HL
+\NC string \NC \letterpercent s \NC abc \NC \cldcontext{string.format("\letterpercent s", "abcd")} \NC \NR
+\NC \NC \letterpercent -8s \NC 123 \NC \cldcontext{string.format("\letterpercent -8s", 123 )} \NC \NR
+\NC \NC \letterpercent 8s \NC 123 \NC \cldcontext{string.format("\letterpercent 8s", 123 )} \NC \NR
+\HL
+\NC float \NC \letterpercent 0.2f \NC 12.345 \NC \cldcontext{string.format("\letterpercent 0.2f",12.345)} \NC \NR
+\NC exponential \NC \letterpercent 0.2e \NC 12.345 \NC \cldcontext{string.format("\letterpercent 0.2e",12.345)} \NC \NR
+\NC \NC \letterpercent 0.2E \NC 12.345 \NC \cldcontext{string.format("\letterpercent 0.2E",12.345)} \NC \NR
+\NC autofloat \NC \letterpercent 0.2g \NC 12.345 \NC \cldcontext{string.format("\letterpercent 0.2g",12.345)} \NC \NR
+\NC \NC \letterpercent 0.2G \NC 12.345 \NC \cldcontext{string.format("\letterpercent 0.2G",12.345)} \NC \NR
+\HL
+\stoptabulate
+
+\startasciimode
+\ShowLuaExampleThree {string} {format} {"U+\letterpercent 05X",2010}
+\stopasciimode
+
+\stopsummary
+
+\startsummary[title={striplines}]
+
+The \type {striplines} function can strip leading and trailing empty lines,
+collapse or delete intermediate empty lines and strips leading and trailing
+spaces. We will demonstrate this with string \type {str}:
+
+\startluacode
+local str = table.concat( {
+" ",
+" aap",
+" noot mies",
+" ",
+" ",
+" wim zus jet",
+"teun vuur gijs",
+" lam kees bok weide",
+" ",
+"does hok duif schapen ",
+" ",
+}, "\n")
+
+document.TempString = str
+
+function document.ShowStrippedString(str)
+ str = string.gsub(str," ","\\allowbreak<sp>\\allowbreak ")
+ str = string.gsub(str,"([\010])","\\allowbreak<lf>\\allowbreak ")
+ context.startalign { "flushleft,verytolerant" }
+ context("{\\tttf %s}",str)
+ context.stopalign()
+end
+
+function document.ShowStrippedBuffer(name,str)
+ context.tobuffer(name,str)
+ context.typebuffer( { name }, { numbering = "line" })
+ context.resetbuffer { name }
+end
+
+function document.ShowStrippedCommand(option)
+ context.type( { style = "ttbf" }, [[utilities.strings.striplines(str,"]] .. option .. [[")]])
+end
+
+context.blank { "big" }
+document.ShowStrippedString(str)
+document.ShowStrippedBuffer("dummy",str)
+
+\stopluacode
+
+The different options for stripping are demonstrated below, We use verbose
+descriptions instead of vague boolean flags.
+
+\startluacode
+local str = document.TempString ; document.TempString = nil
+
+for option in table.sortedhash(utilities.strings.striplinepatterns) do
+ local s = utilities.strings.striplines(str,option)
+ context.blank()
+ document.ShowStrippedCommand(option)
+ context.blank { "big,samepage" }
+ document.ShowStrippedString(s)
+ context.blank { "big,samepage" }
+ document.ShowStrippedBuffer(option,str)
+end
+\stopluacode
+
+You can of course mix usage with the normal \type {context} helper commands, for
+instance put them in buffers. Buffers normally will prune leading and trailing
+empty lines anyway.
+
+\starttyping
+context.tobuffer("dummy",utilities.strings.striplines(str))
+context.typebuffer( { "dummy" }, { numbering = "line" })
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={formatters}]
+
+The \type {format} function discussed before is the built|-|in. As an alternative
+\CONTEXT\ provides an additional formatter that has some extensions. Interesting
+is that that one is often more efficient, although there are cases where the
+speed is comparable. As we run out of keys, some extra ones are a bit counter
+intuitive, like \type {l} for booleans (logical).
+
+\start \setuptype[color=]
+
+\starttabulate[|lB|lT|lT|lT|]
+\HL
+\NC utf character \NC \letterpercent c \NC 322 \NC \cldcontext{"\letterpercent c",322} \NC \NR
+\HL
+\NC string \NC \letterpercent s \NC foo \NC \cldcontext{"\letterpercent s","foo"} \NC \NR
+\NC force tostring \NC \letterpercent S \NC nil \NC \cldcontext{"\letterpercent S",nil} \NC \NR
+\NC quoted string \NC \letterpercent q \NC foo \NC \cldcontext{"\letterpercent q","foo"} \NC \NR
+\NC force quoted string \NC \letterpercent Q \NC nil \NC \cldcontext{"\letterpercent Q",nil} \NC \NR
+\NC \NC \letterpercent N \NC 0123 \NC \cldcontext{"\letterpercent N","0123"} \NC \NR
+\NC automatic quoted \NC \letterpercent a \NC true \NC \cldcontext{"\letterpercent a",true} \NC \NR\NC \NR
+\NC \NC \letterpercent A \NC true \NC \cldcontext{"\letterpercent A",true} \NC \NR\NC \NR
+\NC left aligned utf \NC \letterpercent 30< \NC xx½xx \NC \cldcontext{"\letterpercent 30<","xx½xx"} \NC \NR\NC \NR
+\NC right aligned utf \NC \letterpercent 30> \NC xx½xx \NC \cldcontext{"\letterpercent 30>","xx½xx"} \NC \NR\NC \NR
+\HL
+\NC integer \NC \letterpercent i \NC 1234 \NC \cldcontext{"\letterpercent i",1234} \NC \NR
+\NC integer \NC \letterpercent d \NC 1234 \NC \cldcontext{"\letterpercent d",1234} \NC \NR
+\NC signed number \NC \letterpercent I \NC 1234 \NC \cldcontext{"\letterpercent I",1234} \NC \NR
+\NC rounded number \NC \letterpercent r \NC 1234.56 \NC \cldcontext{"\letterpercent r",1234.56} \NC \NR
+\NC stripped number \NC \letterpercent N \NC 000123 \NC \cldcontext{"\letterpercent N","000123"} \NC \NR
+\NC comma/period float \NC \letterpercent m \NC 12.34 \NC \cldcontext{"\letterpercent m",12.34} \NC \NR
+\NC period/comma float \NC \letterpercent M \NC 12.34 \NC \cldcontext{"\letterpercent M",12.34} \NC \NR
+\HL
+\NC hexadecimal \NC \letterpercent x \NC 1234 \NC \cldcontext{"\letterpercent x",1234} \NC \NR
+\NC \NC \letterpercent X \NC 1234 \NC \cldcontext{"\letterpercent X",1234} \NC \NR
+\NC octal \NC \letterpercent o \NC 1234 \NC \cldcontext{"\letterpercent o",1234} \NC \NR
+\HL
+\NC float \NC \letterpercent 0.2f \NC 12.345 \NC \cldcontext{"\letterpercent 0.2f",12.345} \NC \NR
+\NC formatted float \NC \letterpercent 2.3k \NC 12.3456 \NC \cldcontext{"\letterpercent 2.3f",12.3456} \NC \NR
+\NC checked float \NC \letterpercent 0.2F \NC 12.30 \NC \cldcontext{"\letterpercent 0.2F",12.3} \NC \NR
+\NC exponential \NC \letterpercent .2e \NC 12.345e120 \NC \cldcontext{"\letterpercent 0.2j",12.345e120} \NC \NR
+\NC \NC \letterpercent .2E \NC 12.345e120 \NC \cldcontext{"\letterpercent 0.2J",12.345e120} \NC \NR
+\NC sparse exp \NC \letterpercent 0.2j \NC 12.345e120 \NC \cldcontext{"\letterpercent 0.2j",12.345e120} \NC \NR
+\NC \NC \letterpercent 0.2J \NC 12.345e120 \NC \cldcontext{"\letterpercent 0.2J",12.345e120} \NC \NR
+\NC autofloat \NC \letterpercent g \NC 12.345 \NC \cldcontext{"\letterpercent 0.2J",12.345} \NC \NR
+\NC \NC \letterpercent G \NC 12.345 \NC \cldcontext{"\letterpercent 0.2J",12.345} \NC \NR
+\HL
+\NC unicode value 0x \NC \letterpercent h \NC ł 1234 \NC \cldcontext{"\letterpercent v \letterpercent v", "ł",1234} \NC \NR
+\NC \NC \letterpercent H \NC ł 1234 \NC \cldcontext{"\letterpercent V \letterpercent V", "ł",1234} \NC \NR
+\NC unicode value U+ \NC \letterpercent u \NC ł 1234 \NC \cldcontext{"\letterpercent u \letterpercent u", "ł",1234} \NC \NR
+\NC \NC \letterpercent U \NC ł 1234 \NC \cldcontext{"\letterpercent U \letterpercent U", "ł",1234} \NC \NR
+\HL
+\NC points \NC \letterpercent p \NC 1234567 \NC \cldcontext{"\letterpercent p",1234567} \NC \NR
+\NC basepoints \NC \letterpercent b \NC 1234567 \NC \cldcontext{"\letterpercent b",1234567} \NC \NR
+\HL
+\NC table concat \NC \letterpercent t \NC \arg{1,2,3} \NC \cldcontext{"\letterpercent t",{1,2,3}} \NC \NR
+\NC \NC \letterpercent *t \NC \arg{1,2,3} \NC \cldcontext{"\letterpercent *t",{1,2,3}} \NC \NR
+\NC \NC \letterpercent \arg{ AND }t \NC \arg{a=1,b=3} \NC \cldcontext{"\letterpercent +{ AND }T",{a=1,b=2}} \NC \NR
+\NC table serialize \NC \letterpercent T \NC \arg{1,2,3} \NC \cldcontext{"\letterpercent *t",{1,2,3}} \NC \NR
+\NC \NC \letterpercent T \NC \arg{a=1,b=3} \NC \let|\relax\cldcontext{"\letterpercent T",{a=1,b=2}} \NC \NR
+\NC \NC \letterpercent +T \NC \arg{a=1,b=3} \NC \cldcontext{"\letterpercent [+T]",{a=1,b=2}} \NC \NR
+\HL
+\NC boolean (logic) \NC \letterpercent l \NC "a" == "b" \NC \cldcontext{"\letterpercent l","a"=="b"} \NC \NR
+\NC \NC \letterpercent L \NC "a" == "b" \NC \cldcontext{"\letterpercent L","a"=="b"} \NC \NR
+\HL
+\NC whitespace \NC \letterpercent w \NC 3 \NC \obeyspaces\vl\cldcontext{"\letterpercent w",3}\vl \NC \NR
+\NC \NC \letterpercent 2w \NC 3 \NC \obeyspaces\vl\cldcontext{"\letterpercent 2w",3}\vl \NC \NR
+\NC \NC \letterpercent 4W \NC \NC \obeyspaces\vl\cldcontext{"\letterpercent 4W"}\vl \NC \NR
+\HL
+\NC skip \NC \letterpercent 2z \NC 1,2,3,4 \NC \obeyspaces\vl\cldcontext{"\letterpercent s\letterpercent 2z\letterpercent s",1,2,3,4}\vl \NC \NR
+\HL
+\stoptabulate
+
+\stop
+
+The generic formatters \type {a} and \type {A} convert the argument into a string
+and deals with strings, number, booleans, tables and whatever. We mostly use
+these in tracing. The lowercase variant uses single quotes, and the uppercase
+variant uses double quotes.
+
+A special one is the alignment formatter, which is a variant on the \type {s} one
+that also takes an optional positive of negative number:
+
+\startbuffer
+\startluacode
+context.start()
+context.tttf()
+context.verbatim("[[% 30<]]","xxaxx") context.par()
+context.verbatim("[[% 30<]]","xx½xx") context.par()
+context.verbatim("[[% 30>]]","xxaxx") context.par()
+context.verbatim("[[% 30>]]","xx½xx") context.par()
+context.verbatim("[[%-30<]]","xxaxx") context.par()
+context.verbatim("[[%-30<]]","xx½xx") context.par()
+context.verbatim("[[%-30>]]","xxaxx") context.par()
+context.verbatim("[[%-30>]]","xx½xx") context.par()
+context.stop()
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+There are two more formatters plugged in: \type {!xml!} and \type {!tex!}. These
+are best demonstrated with an example:
+
+\starttyping
+local xf = formatter["xml escaped: %!xml!"]
+local xr = formatter["tex escaped: %!tex!"]
+
+print(xf("x > 1 && x < 10"))
+print(xt("this will cost me $123.00 at least"))
+\stoptyping
+
+weird, this fails when cld-verbatim is there as part of the big thing:
+catcodetable 4 suddenly lacks the comment being a other
+
+The \type {context} command uses the formatter so one can say:
+
+\startbuffer
+\startluacode
+context("first some xml: %!xml!, and now some %!tex!",
+ "x > 1 && x < 10", "this will cost me $123.00 at least")
+\stopluacode
+\stopbuffer
+
+\typebuffer
+
+This renders as follows:
+
+\blank \getbuffer \blank
+
+You can extend the formatter but we advise you not to do that unless you're sure
+what you're doing. You never know what \CONTEXT\ itself might add for its own
+benefit.
+
+However, you can define your own formatter and add to that without interference.
+In fact, the main formatter is just defined that way. This is how it works:
+
+\startbuffer[definition]
+local MyFormatter = utilities.strings.formatters.new()
+
+utilities.strings.formatters.add (
+ MyFormatter,
+ "upper",
+ "global.string.upper(%s)"
+)
+\stopbuffer
+
+\typebuffer[definition]
+
+Now you can use this one as:
+
+\startbuffer[usage]
+context.bold(MyFormatter["It's %s or %!upper!."]("this","that"))
+\stopbuffer
+
+\typebuffer[usage]
+
+\blank \ctxluabuffer[definition,usage] \blank
+
+Because we're running inside \CONTEXT, a better definition would be this:
+
+\startbuffer
+local MyFormatter = utilities.strings.formatters.new()
+
+utilities.strings.formatters.add (
+ MyFormatter,
+ "uc",
+ "myupper(%s)",
+ -- "local myupper = global.characters.upper"
+ { myupper = global.characters.upper }
+)
+
+utilities.strings.formatters.add (
+ MyFormatter,
+ "lc",
+ "mylower(%s)",
+ -- "local mylower = global.characters.lower"
+ { mylower = global.characters.lower }
+)
+
+utilities.strings.formatters.add (
+ MyFormatter,
+ "sh",
+ "myshaped(%s)",
+ -- "local myshaped = global.characters.shaped"
+ { myshaped = global.characters.shaped }
+)
+
+context(MyFormatter["Uppercased: %!uc!"]("ÀÁÂÃÄÅàáâãäå"))
+context.par()
+context(MyFormatter["Lowercased: %!lc!"]("ÀÁÂÃÄÅàáâãäå"))
+context.par()
+context(MyFormatter["Reduced: %!sh!"]("ÀÁÂÃÄÅàáâãäå"))
+\stopbuffer
+
+\typebuffer
+
+The last arguments creates shortcuts. As expected we get:
+
+\blank \ctxluabuffer \blank
+
+Of course you can also apply the casing functions directly so in practice you
+shouldn't use formatters without need. Among the advantages of using formatters
+are:
+
+\startitemize[packed]
+\startitem They provide a level of abstraction. \stopitem
+\startitem They can replace multiple calls to \type {\context}. \stopitem
+\startitem Sometimes they make source code look better. \stopitem
+\startitem Using them is often more efficient and faster. \stopitem
+\stopitemize
+
+The last argument might sound strange but considering the overhead involved in
+the \type {context} (related) functions, doing more in one step has benefits.
+Also, formatters are implemented quite efficiently, so their overhead can be
+neglected.
+
+In the examples you see that a formatter extension is itself a template.
+
+\startbuffer
+local FakeXML = utilities.strings.formatters.new()
+
+utilities.strings.formatters.add(FakeXML,"b",[["<" ..%s..">" ]])
+utilities.strings.formatters.add(FakeXML,"e",[["</"..%s..">" ]])
+utilities.strings.formatters.add(FakeXML,"n",[["<" ..%s.."/>"]])
+
+context(FakeXML["It looks like %!b!xml%!e! doesn't it?"]("it","it"))
+\stopbuffer
+
+\typebuffer
+
+This gives: \ctxluabuffer. Of course we could go over the top here:
+
+\startbuffer
+local FakeXML = utilities.strings.formatters.new()
+
+local stack = { }
+
+function document.f_b(s)
+ table.insert(stack,s)
+ return "<" .. s .. ">"
+end
+
+function document.f_e()
+ return "</" .. table.remove(stack) .. ">"
+end
+
+utilities.strings.formatters.add(FakeXML,"b",[[global.document.f_b(%s)]])
+utilities.strings.formatters.add(FakeXML,"e",[[global.document.f_e()]])
+
+context(FakeXML["It looks like %1!b!xml%0!e! doesn't it?"]("it"))
+\stopbuffer
+
+\typebuffer
+
+This gives: \ctxluabuffer. Such a template look horrible, although it's not too
+far from the regular format syntax: just compare \type {%1f} with \type {%1!e!}.
+The zero trick permits us to inject information that we've put on the stack. As
+this kind of duplicate usage might occur most, a better solution is available:
+
+\startbuffer
+local FakeXML = utilities.strings.formatters.new()
+
+utilities.strings.formatters.add(FakeXML,"b",[["<" .. %s .. ">"]])
+utilities.strings.formatters.add(FakeXML,"e",[["</" .. %s .. ">"]])
+
+context(FakeXML["It looks like %!b!xml%-1!e! doesn't it?"]("it"))
+\stopbuffer
+
+\typebuffer
+
+We get: \ctxluabuffer. Anyhow, in most cases you will never feel the need for
+such hackery and the regular formatter works fine. Adding this extension
+mechanism was rather trivial and it doesn't influence the performance.
+
+In \CONTEXT\ we have a few more extensions:
+
+\starttyping
+utilities.strings.formatters.add (
+ strings.formatters, "unichr",
+ [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]]
+)
+
+utilities.strings.formatters.add (
+ strings.formatters, "chruni",
+ [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]]
+)
+\stoptyping
+
+This one is used in messages:
+
+\startbuffer
+context("Missing character %!chruni! in font.",234) context.par()
+context("Missing character %!unichr! in font.",234)
+\stopbuffer
+
+\typebuffer
+
+This shows up as:
+
+\blank \getbuffer \blank
+
+If you look closely to the definition, you will notice that we use \type {%s}
+twice. This is a feature of the definer function: if only one argument is
+picked up (which is default) then the replacement format can use that two
+times. Because we use a format in the constructor, we need to escape the
+percent sign there.
+
+\stopsummary
+
+\startsummary[title={strip}]
+
+This function removes any leading and trailing whitespace characters.
+
+\starttyping
+local s = string.strip(str)
+\stoptyping
+
+\ShowLuaExampleThree {string} {strip} {" lua + tex = luatex "}
+
+\stopsummary
+
+\startsummary[title={split splitlines checkedsplit}]
+
+The line splitter is a special case of the generic splitter. The \type {split}
+function can get a string as well an \type {lpeg} pattern. The \type
+{checkedsplit} function removes empty substrings.
+
+\starttyping
+local t = string.split (str, pattern)
+local t = string.split (str, lpeg)
+local t = string.checkedsplit (str, lpeg)
+local t = string.splitlines (str)
+\stoptyping
+
+\start \let\ntex\relax % hack
+
+\ShowLuaExampleTwo {string} {split} {"a, b,c, d", ","}
+\ShowLuaExampleTwo {string} {split} {"p.q,r", lpeg.S(",.")}
+\ShowLuaExampleTwo {string} {checkedsplit} {";one;;two", ";"}
+\ShowLuaExampleTwo {string} {splitlines} {"lua\ntex nic"}
+
+\stop
+
+\stopsummary
+
+\startsummary[title={quoted unquoted}]
+
+You will hardly need these functions. The \type {quoted} function can normally be
+avoided using the \type {format} pattern \type {%q}. The \type {unquoted}
+function removes single or double quotes but only when the string starts and ends
+with the same quote.
+
+\starttyping
+local q = string.quoted (str)
+local u = string.unquoted(str)
+\stoptyping
+
+\ShowLuaExampleThree {string} {quoted} {[[test]]}
+\ShowLuaExampleThree {string} {quoted} {[[test"test]]}
+\ShowLuaExampleThree {string} {unquoted} {[["test]]}
+\ShowLuaExampleThree {string} {unquoted} {[["t\"est"]]}
+\ShowLuaExampleThree {string} {unquoted} {[["t\"est"x]]}
+\ShowLuaExampleThree {string} {unquoted} {"\'test\'"}
+
+\stopsummary
+
+\startsummary[title={count}]
+
+The function \type {count} returns the number of times that a given pattern
+occurs. Beware: if you want to deal with \UTF\ strings, you need the variant that
+sits in the \type {lpeg} namespace.
+
+\starttyping
+local n = count(str,pattern)
+\stoptyping
+
+\ShowLuaExampleThree {string} {count} {"test me", "e"}
+
+\stopsummary
+
+\startsummary[title={limit}]
+
+This function can be handy when you need to print messages that can be rather
+long. By default, three periods are appended when the string is chopped.
+
+\starttyping
+print(limit(str,max,sentinel)
+\stoptyping
+
+\ShowLuaExampleThree {string} {limit} {"too long", 6}
+\ShowLuaExampleThree {string} {limit} {"too long", 6, " (etc)"}
+
+\stopsummary
+
+\startsummary[title={is_empty}]
+
+A string considered empty by this function when its length is zero or when it
+only contains spaces.
+
+\starttyping
+if is_empty(str) then ... end
+\stoptyping
+
+\ShowLuaExampleThree {string} {is_empty} {""}
+\ShowLuaExampleThree {string} {is_empty} {" "}
+\ShowLuaExampleThree {string} {is_empty} {" ? "}
+
+\stopsummary
+
+\startsummary[title={escapedpattern topattern}]
+
+These two functions are rather specialized. They come in handy when you need to
+escape a pattern, i.e.\ prefix characters with a special meaning by a \type {%}.
+
+\starttyping
+local e = escapedpattern(str, simple)
+local p = topattern (str, lowercase, strict)
+\stoptyping
+
+The simple variant does less escaping (only \type {-.?*} and is for instance used
+in wildcard patterns when globbing directories. The \type {topattern} function
+always does the simple escape. A strict pattern gets anchored to the beginning
+and end. If you want to see what these functions do you can best look at their
+implementation.
+
+\stopsummary
+
+% strings.tabtospace(str,n)
+% strings.striplong
+
+\stopsection
+
+\startsection[title=\UTF]
+
+We used to have the \type {slunicode} library available but as most of it is not
+used and because it has a somewhat fuzzy state, we will no longer rely on it. In
+fact we only used a few functions in the \type {utf} namespace so as \CONTEXT\
+user you'd better stick to what is presented here. You don't have to worry how
+they are implemented. Depending on the version of \LUATEX\ it can be that a
+library, a native function, or \LPEG is used.
+
+\startsummary[title={char byte}]
+
+As \UTF\ is a multibyte encoding the term char in fact refers to a \LUA\
+string of one upto four 8|-|bit characters.
+
+\starttyping
+local b = utf.byte("å")
+local c = utf.char(0xE5)
+\stoptyping
+
+The number of places in \CONTEXT\ where do such conversion is not that large:
+it happens mostly in tracing messages.
+
+\starttyping
+logs.report("panic","the character U+%05X is used",utf.byte("æ"))
+\stoptyping
+
+\ShowLuaExampleThree {utf} {byte} {"æ"}
+\ShowLuaExampleThree {utf} {char} {0xE6}
+
+\stopsummary
+
+\startsummary[title={sub}]
+
+If you need to take a slice of an \UTF\ encoded string the \type {sub} function
+can come in handy. This function takes a string and a range defined by two
+numbers. Negative numbers count from the end of the string.
+
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",1,7}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0,7}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0,9}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",4}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0,0}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",4,4}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",4,0}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",-3,0}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0,-3}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",-5,-3}
+\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",-3}
+
+\stopsummary
+
+\startsummary[title={len}]
+
+There are probably not that many people that can instantly see how many bytes the
+string in the following example takes:
+
+\starttyping
+local l = utf.len("ÀÁÂÃÄÅàáâãäå")
+\stoptyping
+
+Programming languages use \ASCII\ mostly so there each characters takes one byte.
+In \CJK\ scripts however, you end up with much longer sequences. If you ever did
+some typesetting of such scripts you have noticed that the number of characters
+on a page is less than in the case of a Latin script. As information is coded
+in less characters, effectively the source of a Latin or \CJK\ document will not
+differ that much.
+
+\ShowLuaExampleThree {utf} {len} {"ÒÓÔÕÖòóôõö"}
+
+\stopsummary
+
+\startsummary[title={values characters}]
+
+There are two iterators that deal with \UTF. In \LUATEX\ these are extensions to
+the \type {string} library but for consistency we've move them to the \type {utf}
+namespace.
+
+The following function loops over the \UTF\ characters in a string and returns
+the \UNICODE\ number in \type {u}:
+
+\starttyping
+for u in utf.values(str) do
+ ... -- u is a number
+end
+\stoptyping
+
+The next one returns a string \type {c} that has one or more characters as \UTF\
+characters can have upto 4 bytes.
+
+\starttyping
+for c in utf.characters(str) do
+ ... -- c is a string
+end
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={ustring xstring tocodes}]
+
+These functions are mostly useful for logging where we want to see the \UNICODE\
+number.
+
+\ShowLuaExampleThree {utf} {ustring} {0xE6}
+\ShowLuaExampleThree {utf} {ustring} {"ù"}
+\ShowLuaExampleThree {utf} {xstring} {0xE6}
+\ShowLuaExampleThree {utf} {xstring} {"à"}
+\ShowLuaExampleThree {utf} {tocodes} {"ùúü"}
+\ShowLuaExampleThree {utf} {tocodes} {"àáä",""}
+\ShowLuaExampleThree {utf} {tocodes} {"òóö","+"}
+
+\stopsummary
+
+\startsummary[title={split splitlines totable}]
+
+The \type {split} function splits a sequence of \UTF\ characters into a table
+which one character per slot. The \type {splitlines} does the same but each slot
+has a line instead. The \type {totable} function is similar to \type {split}, but
+the later strips an optionally present \UTF\ bom.
+
+\ShowLuaExampleThree {utf} {split} {"òóö"}
+
+\stopsummary
+
+\startsummary[title={count}]
+
+This function counts the number of times that a given substring occurs in a
+string. The patterns can be a string or an \LPEG\ pattern.
+
+\ShowLuaExampleThree {utf} {count} {"òóöòóöòóö","ö"}
+\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.P("á") + lpeg.P("à")}
+
+\stopsummary
+
+\startsummary[title={remapper replacer substituter}]
+
+With \type {remapper} you can create a remapping function that remaps a given
+string using a (hash) table.
+
+\starttyping
+local remap = utf.remapper { a = 'd', b = "c", c = "b", d = "a" }
+
+print(remap("abcd 1234 abcd"))
+\stoptyping
+
+A remapper checks each character against the given mapping table. Its cousin
+\type {replacer} is more efficient and skips non matches. The \type {substituter}
+function only does a quick check first and avoids building a string with no
+replacements. That one is much faster when you expect not that many replacements.
+
+The \type {replacer} and \type {substituter} functions take table as argument
+and an indexed as well as hashed one are acceptable. In fact you can even do
+things like this:
+
+\starttyping
+local rep = utf.replacer { [lpeg.patterns.digit] = "!" }
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={is_valid}]
+
+This function returns false if the argument is no valid \UTF\ string. As \LUATEX\
+is pretty strict with respect to the input, this function is only useful when
+dealing with external files.
+
+\starttyping
+function checkfile(filename)
+ local data = io.loaddata(filename)
+ if data and data ~= "" and not utf.is_valid(data) then
+ logs.report("error","file %q contains invalid utf",filename)
+ end
+end
+\stoptyping
+
+\stopsummary
+
+% not that relevant:
+%
+% -- utf.filetype
+% -- string.toutf
+
+\stopsection
+
+\startsection[title=Numbers and bits]
+
+In the \type {number} namespace we collect some helpers that deal with numbers as
+well as bits. Starting with \LUA\ 5.2 a library \type {bit32} is but the language
+itself doesn't provide for them via operators: the library uses functions to
+manipulate numbers upto 2\high{32}. In the latest \LUATEX\ you can use the new
+bit related operators.
+
+% For advanced bit manipulations you should use the \type {bit32} library, otherwise
+% it's best to stick to the functions described here.
+%
+% \startsummary[title={hasbit setbit clearbit}]
+%
+% As bitsets are numbers you will also use numbers to qualify them. So, if you want to
+% set bits 1, 4 and 8, you can to that using the following specification:
+%
+% \starttyping
+% local b = 1 + 4 + 8 -- 0x1 + 0x4 + 0x8
+% local b = 13 -- or 0xC
+% \stoptyping
+%
+% However, changing one bit by adding a number to an existing doesn't work out that well
+% if that number already has that bit set. Instead we use:
+%
+% \starttyping
+% local b = number.setbit(b,0x4)
+% \stoptyping
+%
+% In a similar fashion you can turn of a bit:
+%
+% \starttyping
+% local b = number.clearbit(b,0x4)
+% \stoptyping
+%
+% Testing for a bit(set) is done as follows:
+%
+% \starttyping
+% local okay = number.hasbit(b,0x4)
+% \stoptyping
+%
+% \stopsummary
+%
+% \startsummary[title={bit}]
+%
+% Where the previously mentioned helpers work with numbers representing one or more
+% bits, it is sometimes handy to work with positions. The \type {bit} function
+% returns the associated number value.
+%
+% \ShowLuaExampleThree {number} {bit} {5}
+%
+% \stopsummary
+
+\startsummary[title={tobitstring}]
+
+There is no format option to go from number to bits in terms of zeros and ones so
+we provide a helper: \type {tobitsting}.
+
+\ShowLuaExampleThree {number} {tobitstring} {2013}
+\ShowLuaExampleThree {number} {tobitstring} {2013,3}
+\ShowLuaExampleThree {number} {tobitstring} {2013,1}
+
+\stopsummary
+
+% \startsummary[title={bits}]
+%
+% If you ever want to convert a bitset into a table containing the set bits you can
+% use this function.
+%
+% \ShowLuaExampleTwo {number} {bits} {11}
+%
+% \stopsummary
+%
+% \startsummary[title={toset}]
+%
+% A string or number can be split into digits with \type {toset}. Beware, this
+% function does not return a function but multiple numbers
+%
+% \starttyping
+% local a, b, c, d = number.toset("1001")
+% \stoptyping
+%
+% The returned values are either numbers or \type {nil} when an valid digit is
+% seen.
+%
+% \ShowLuaExampleSeven {number} {toset} {100101}
+% \ShowLuaExampleSeven {number} {toset} {"100101"}
+% \ShowLuaExampleSeven {number} {toset} {"21546"}
+%
+% \stopsummary
+
+\startsummary[title={valid}]
+
+This function can be used to check or convert a number, for instance in user
+interfaces.
+
+\ShowLuaExampleThree {number} {valid} {12}
+\ShowLuaExampleThree {number} {valid} {"34"}
+\ShowLuaExampleThree {number} {valid} {"ab",56}
+
+\stopsummary
+
+\stopsection
+
+\startsection[title=\LPEG\ patterns]
+
+For \LUATEX\ and \CONTEXT\ \MKIV\ the \type {lpeg} library came at the right
+moment as we can use it in lots of places. An in|-|depth discussion makes no
+sense as it's easier to look into \type {l-lpeg.lua}, so we stick to an overview.
+\footnote {If you search the web for \type {lua lpeg} you will end up at the
+official documentation and tutorial.} Most functions return an \type {lpeg}
+object that can be used in a match. In time critical situations it's more
+efficient to use the match on a predefined pattern that to create the pattern new
+each time. Patterns are cached so there is no penalty in predefining a pattern.
+So, in the following example, the \type {splitter} that splits at the asterisk
+will only be created once.
+
+\starttyping
+local splitter_1 = lpeg.splitat("*")
+local splitter_2 = lpeg.splitat("*")
+
+local n, m = lpeg.match(splitter_1,"2*4")
+local n, m = lpeg.match(splitter_2,"2*4")
+\stoptyping
+
+\startsummary[title={[lua] match print P R S V C Cc Cs ...}]
+
+The \type {match} function does the real work. Its first argument is a \type
+{lpeg} object that is created using the functions with the short uppercase names.
+
+\starttyping
+local P, R, C, Ct = lpeg.P, lpeg.R, lpeg.C, lpeg.Ct
+
+local pattern = Ct((P("[") * C(R("az")^0) * P(']') + P(1))^0)
+
+local words = lpeg.match(pattern,"a [first] and [second] word")
+\stoptyping
+
+In this example the words between square brackets are collected in a table. There
+are lots of examples of \type {lpeg} in the \CONTEXT\ code base.
+
+\stopsummary
+
+\startsummary[title={anywhere}]
+
+\starttyping
+local p = anywhere(pattern)
+\stoptyping
+
+\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct((lpeg.anywhere("->")/"!")^0), "oeps->what->more"}
+
+\stopsummary
+
+\startsummary[title={splitter splitat firstofsplit secondofsplit}]
+
+The \type {splitter} function returns a pattern where each match gets an action
+applied. The action can be a function, table or string.
+
+\starttyping
+local p = splitter(pattern, action)
+\stoptyping
+
+The \type {splitat} function returns a pattern that will return the split off
+parts. Unless the second argument is \type {true} the splitter keeps splitting
+
+\starttyping
+local p = splitat(separator,single)
+\stoptyping
+
+When you need to split off a prefix (for instance in a label) you can use:
+
+\starttyping
+local p = firstofsplit(separator)
+local p = secondofsplit(separator)
+\stoptyping
+
+The first function returns the original when there is no match but the second
+function returns \type {nil} instead.
+
+\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct(lpeg.splitat("->",false)), "oeps->what->more"}
+\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct(lpeg.splitat("->",false)), "oeps"}
+\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct(lpeg.splitat("->",true)), "oeps->what->more"}
+\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct(lpeg.splitat("->",true)), "oeps"}
+
+\ShowLuaExampleThree {lpeg} {match} {lpeg.firstofsplit(":"), "before:after"}
+\ShowLuaExampleThree {lpeg} {match} {lpeg.firstofsplit(":"), "whatever"}
+\ShowLuaExampleThree {lpeg} {match} {lpeg.secondofsplit(":"), "before:after"}
+\ShowLuaExampleThree {lpeg} {match} {lpeg.secondofsplit(":"), "whatever"}
+
+\stopsummary
+
+\startsummary[title={split checkedsplit}]
+
+The next two functions have counterparts in the \type {string} namespace. They
+return a table with the split parts. The second function omits empty parts.
+
+\starttyping
+local t = split (separator,str)
+local t = checkedsplit(separator,str)
+\stoptyping
+
+\ShowLuaExampleTwo {lpeg} {split} {",","a,b,c"}
+\ShowLuaExampleTwo {lpeg} {split} {",",",a,,b,c,"}
+\ShowLuaExampleTwo {lpeg} {checkedsplit} {",",",a,,b,c,"}
+
+\stopsummary
+
+\startsummary[title={stripper keeper replacer}]
+
+These three functions return patterns that manipulate a string. The \type
+{replacer} gets a mapping table passed.
+
+\starttyping
+local p = stripper(str or pattern)
+local p = keeper (str or pattern)
+local p = replacer(mapping)
+\stoptyping
+
+\ShowLuaExampleThree {lpeg} {match} {lpeg.stripper(lpeg.R("az")), "[-a-b-c-d-]"}
+\ShowLuaExampleThree {lpeg} {match} {lpeg.stripper("ab"), "[-a-b-c-d-]"}
+\ShowLuaExampleThree {lpeg} {match} {lpeg.keeper(lpeg.R("az")), "[-a-b-c-d-]"}
+\ShowLuaExampleThree {lpeg} {match} {lpeg.keeper("ab"), "[-a-b-c-d-]"}
+\ShowLuaExampleThree {lpeg} {match} {lpeg.replacer{{"a","p"},{"b","q"}}, "[-a-b-c-d-]"}
+
+\stopsummary
+
+\startsummary[title={balancer}]
+
+One of the nice things about \type {lpeg} is that it can handle all kind of
+balanced input. So, a function is provided that returns a balancer pattern:
+
+\starttyping
+local p = balancer(left,right)
+\stoptyping
+
+\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct((lpeg.C(lpeg.balancer("{","}"))+1)^0),"{a} {b{c}}"}
+\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct((lpeg.C(lpeg.balancer("((","]"))+1)^0),"((a] ((b((c]]"}
+
+\stopsummary
+
+\startsummary[title={counter}]
+
+The \type {counter} function returns a function that returns the length of a
+given string. The \type {count} function differs from its counterpart living in
+the \type {string} namespace in that it deals with \UTF\ and accepts strings as
+well as patterns.
+
+\starttyping
+local fnc = counter(lpeg.P("á") + lpeg.P("à"))
+local len = fnc("äáàa")
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={UP US UR}]
+
+In order to make working with \UTF-8 input somewhat more convenient a few helpers
+are provided.
+
+\starttyping
+local p = lpeg.UP(utfstring)
+local p = lpeg.US(utfstring)
+local p = lpeg.UR(utfpair)
+local p = lpeg.UR(first,last)
+\stoptyping
+
+\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.UP("áà")}
+\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.US("àá")}
+\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.UR("aá")}
+\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.UR("àá")}
+\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.UR(0x0000,0xFFFF)}
+
+\startsummary[title={patterns}]
+
+The following patterns are available in the \type {patterns} table in the \type
+{lpeg} namespace:
+
+\startluacode
+context.startalignment { "flushleft" }
+local done = false
+for k, v in table.sortedpairs(lpeg.patterns) do
+ if done then
+ context.space()
+ else
+ done = true
+ end
+ context.type(k)
+end
+context.stopalignment()
+\stopluacode
+
+There will probably be more of them in the future.
+
+\stopsummary
+
+\stopsection
+
+\startsection[title=IO]
+
+The \type {io} library is extended with a couple of functions as well and
+variables but first we mention a few predefined functions.
+
+\startsummary[title={[lua] open popen...}]
+
+The IO library deals with in- and output from the console and
+files.
+
+\starttyping
+local f = io.open(filename)
+\stoptyping
+
+When the call succeeds \type {f} is a file object. You close this file
+with:
+
+\starttyping
+f:close()
+\stoptyping
+
+Reading from a file is done with \type {f:read(...)} and writing to a file with
+\type {f:write(...)}. In order to write to a file, when opening a second argument
+has to be given, often \type {wb} for writing (binary) data. Although there are
+more efficient ways, you can use the \type {f:lines()} iterator to process a file
+line by line.
+
+You can open a process with \type {io.popen} but dealing with this one depends a
+bit on the operating system.
+
+\stopsummary
+
+\startsummary[title={fileseparator pathseparator}]
+
+The value of the following two strings depends on the operating system that is
+used.
+
+\starttyping
+io.fileseparator
+io.pathseparator
+\stoptyping
+
+\ShowLuaExampleFive {io} {fileseparator}
+\ShowLuaExampleFive {io} {pathseparator}
+
+\stopsummary
+
+\startsummary[title={loaddata savedata}]
+
+These two functions save you some programming. The first function loads a whole
+file in a string. By default the file is loaded in binary mode, but when the
+second argument is \type {true}, some interpretation takes place (for instance
+line endings). In practice the second argument can best be left alone.
+
+\starttyping
+io.loaddata(filename,textmode)
+\stoptyping
+
+Saving the data is done with:
+
+\starttyping
+io.savedata(filename,str)
+io.savedata(filename,tab,joiner)
+\stoptyping
+
+When a table is given, you can optionally specify a string that
+ends up between the elements that make the table.
+
+\stopsummary
+
+\startsummary[title={exists size noflines}]
+
+These three function don't need much comment.
+
+\starttyping
+io.exists(filename)
+io.size(filename)
+io.noflines(fileobject)
+io.noflines(filename)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={characters bytes readnumber readstring}]
+
+When I wrote the icc profile loader, I needed a few helpers for reading strings
+of a certain length and numbers of a given width. Both accept five values of
+\type {n}: \type {-4}, \type {-2}, \type {1}, \type {2} and \type {4} where the
+negative values swap the characters or bytes.
+
+\starttyping
+io.characters(f,n) --
+io.bytes(f,n)
+\stoptyping
+
+The function \type {readnumber} accepts five sizes: \type {1}, \type {2}, \type
+{4}, \type {8}, \type {12}. The string function handles any size and strings zero
+bytes from the string.
+
+\starttyping
+io.readnumber(f,size)
+io.readstring(f,size)
+\stoptyping
+
+Optionally you can give the position where the reading has to start:
+
+\starttyping
+io.readnumber(f,position,size)
+io.readstring(f,position,size)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={ask}]
+
+In practice you will probably make your own variant of the following function,
+but at least a template is there:
+
+\starttyping
+io.ask(question,default,options)
+\stoptyping
+
+For example:
+
+\starttyping
+local answer = io.ask("choice", "two", { "one", "two" })
+\stoptyping
+
+\stopsummary
+
+\stopsection
+
+\startsection[title=File]
+
+The file library is one of the larger core libraries that comes with
+\CONTEXT.
+
+\startsummary[title={dirname basename extname nameonly}]
+
+We start with a few filename manipulators.
+
+\starttyping
+local path = file.dirname(name,default)
+local base = file.basename(name)
+local suffix = file.extname(name,default) -- or file.suffix
+local name = file.nameonly(name)
+\stoptyping
+
+\ShowLuaExampleThree {file} {dirname} {"/data/temp/whatever.cld"}
+\ShowLuaExampleThree {file} {dirname} {"c:/data/temp/whatever.cld"}
+\ShowLuaExampleThree {file} {basename} {"/data/temp/whatever.cld"}
+\ShowLuaExampleThree {file} {extname} {"c:/data/temp/whatever.cld"}
+\ShowLuaExampleThree {file} {nameonly} {"/data/temp/whatever.cld"}
+
+\stopsummary
+
+\startsummary[title={addsuffix replacesuffix}]
+
+These functions are used quite often:
+
+\starttyping
+local filename = file.addsuffix(filename, suffix, criterium)
+local filename = file.replacesuffix(filename, suffix)
+\stoptyping
+
+The first one adds a suffix unless one is present. When \type {criterium} is
+\type {true} no checking is done and the suffix is always appended. The second
+function replaces the current suffix or add one when there is none.
+
+\ShowLuaExampleThree {file} {addsuffix} {"whatever","cld"}
+\ShowLuaExampleThree {file} {addsuffix} {"whatever.tex","cld"}
+\ShowLuaExampleThree {file} {addsuffix} {"whatever.tex","cld",true}
+
+\ShowLuaExampleThree {file} {replacesuffix} {"whatever","cld"}
+\ShowLuaExampleThree {file} {replacesuffix} {"whatever.tex","cld"}
+
+\stopsummary
+
+\startsummary[title={is_writable is_readable}]
+
+These two test the nature of a file:
+
+\starttyping
+file.is_writable(name)
+file.is_readable(name)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={splitname join collapsepath}]
+
+Instead of splitting off individual components you can get them all in one go:
+
+\starttyping
+local drive, path, base, suffix = file.splitname(name)
+\stoptyping
+
+The \type {drive} variable is empty on operating systems other than \MSWINDOWS.
+Such components are joined with the function:
+
+\starttyping
+file.join(...)
+\stoptyping
+
+The given snippets are joined using the \type {/} as this is
+rather platform independent. Some checking takes place in order
+to make sure that nu funny paths result from this. There is
+also \type {collapsepath} that does some cleanup on a path
+with relative components, like \type {..}.
+
+\ShowLuaExampleSix {file} {splitname} {"a:/b/c/d.e"}
+\ShowLuaExampleThree {file} {join} {"a","b","c.d"}
+\ShowLuaExampleThree {file} {collapsepath} {"a/b/../c.d"}
+\ShowLuaExampleThree {file} {collapsepath} {"a/b/../c.d",true}
+
+\stopsummary
+
+\startsummary[title={splitpath joinpath}]
+
+By default splitting a execution path specification is done using the operating
+system dependant separator, but you can force one as well:
+
+\starttyping
+file.splitpath(str,separator)
+\stoptyping
+
+The reverse operation is done with:
+
+\starttyping
+file.joinpath(tab,separator)
+\stoptyping
+
+Beware: in the following examples the separator is system dependent so
+the outcome depends on the platform you run on.
+
+\ShowLuaExampleTwo {file} {splitpath} {"a:b:c"}
+\ShowLuaExampleTwo {file} {splitpath} {"a;b;c"}
+\ShowLuaExampleThree {file} {joinpath} {{"a","b","c"}}
+
+\stopsummary
+
+\startsummary[title={robustname}]
+
+In workflows filenames with special characters can be a pain so the following
+function replaces characters other than letters, digits, periods, slashes and
+hyphens by hyphens.
+
+\starttyping
+file.robustname(str,strict)
+\stoptyping
+
+\ShowLuaExampleThree {file} {robustname} {"We don't like this!"}
+\ShowLuaExampleThree {file} {robustname} {"We don't like this!",true}
+
+\stopsummary
+
+\startsummary[title={readdata writedata}]
+
+These two functions are duplicates of functions with the
+same name in the \type {io} library.
+
+\stopsummary
+
+\startsummary[title={copy}]
+
+There is not much to comment on this one:
+
+\starttyping
+file.copy(oldname,newname)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={is_qualified_path is_rootbased_path}]
+
+A qualified path has at least one directory component while a rootbased path is
+anchored to the root of a filesystem or drive.
+
+\starttyping
+file.is_qualified_path(filename)
+file.is_rootbased_path(filename)
+\stoptyping
+
+\ShowLuaExampleThree {file} {is_qualified_path} {"a"}
+\ShowLuaExampleThree {file} {is_qualified_path} {"a/b"}
+\ShowLuaExampleThree {file} {is_rootbased_path} {"a/b"}
+\ShowLuaExampleThree {file} {is_rootbased_path} {"/a/b"}
+
+\stopsummary
+
+\stopsection
+
+\startsection[title=Dir]
+
+The \type {dir} library uses functions of the \type {lfs} library that is linked
+into \LUATEX.
+
+\startsummary[title={current}]
+
+This returns the current directory:
+
+\starttyping
+dir.current()
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={glob globpattern globfiles}]
+
+% not yet documented: dir.collectpattern(path,patt,recurse,result) -- collects tree
+
+The \type {glob} function collects files with names that match a given pattern.
+The pattern can have wildcards: \type {*} (oen of more characters), \type {?}
+(one character) or \type {**} (one or more directories). You can pass the
+function a string or a table with strings. Optionally a second argument can be
+passed, a table that the results are appended to.
+
+\starttyping
+local files = dir.glob(pattern,target)
+local files = dir.glob({pattern,...},target)
+\stoptyping
+
+The target is optional and often you end up with simple calls like:
+
+\starttyping
+local files = dir.glob("*.tex")
+\stoptyping
+
+There is a more extensive version where you start at a path, and applies an
+action to each file that matches the pattern. You can either or not force
+recursion.
+
+\starttyping
+dir.globpattern(path,patt,recurse,action)
+\stoptyping
+
+The \type {globfiles} function collects matches in a table that is returned at
+the end. You can pass an existing table as last argument. The first argument is
+the starting path, the second arguments controls analyzing directories and the
+third argument has to be a function that gets a name passed and is supposed to
+return \type {true} or \type {false}. This function determines what gets
+collected.
+
+\starttyping
+dir.globfiles(path,recurse,func,files)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={makedirs}]
+
+With \type {makedirs} you can create the given directory. If more than one
+name is given they are concatinated.
+
+\starttyping
+dir.makedirs(name,...)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={expandname}]
+
+This function tries to resolve the given path, including relative paths.
+
+\starttyping
+dir.expandname(str)
+\stoptyping
+
+\ShowLuaExampleThree {dir} {expandname} {"."}
+
+\stopsummary
+
+\stopsection
+
+\startsection[title=URL]
+
+\startsummary[title={split hashed construct}]
+
+This is a specialized library. You can split an \type {url} into its components.
+An \URL\ is constructed like this:
+
+\starttyping
+foo://example.com:2010/alpha/beta?gamma=delta#epsilon
+\stoptyping
+
+\starttabulate[|T|T|]
+\NC scheme \NC foo:// \NC \NR
+\NC authority \NC example.com:2010 \NC \NR
+\NC path \NC /alpha/beta \NC \NR
+\NC query \NC gamma=delta \NC \NR
+\NC fragment \NC epsilon \NC \NR
+\stoptabulate
+
+A string is split into a hash table with these keys using the following function:
+
+\starttyping
+url.hashed(str)
+\stoptyping
+
+or in strings with:
+
+\starttyping
+url.split(str)
+\stoptyping
+
+The hash variant is more tolerant than the split. In the hash
+there is also a key \type {original} that holds the original \URL\
+and and the boolean \type {noscheme} indicates if there is a
+scheme at all.
+
+The reverse operation is done with:
+
+\starttyping
+url.construct(hash)
+\stoptyping
+
+\startasciimode
+\ShowLuaExampleTwo {url} {hashed} {"foo://example.com:2010/alpha/beta?gamma=delta#epsilon"}
+\ShowLuaExampleTwo {url} {hashed} {"alpha/beta"}
+\ShowLuaExampleTwo {url} {split} {"foo://example.com:2010/alpha/beta?gamma=delta#epsilon"}
+\ShowLuaExampleTwo {url} {split} {"alpha/beta"}
+\stopasciimode
+
+\startsummary[title={hasscheme addscheme filename query}]
+
+There are a couple of helpers and their names speaks for themselves:
+
+\starttyping
+url.hasscheme(str)
+url.addscheme(str,scheme)
+url.filename(filename)
+url.query(str)
+\stoptyping
+
+\ShowLuaExampleThree {url} {hasscheme} {"http://www.pragma-ade.com/cow.png"}
+\ShowLuaExampleThree {url} {hasscheme} {"www.pragma-ade.com/cow.png"}
+\ShowLuaExampleThree {url} {addscheme} {"www.pragma-ade.com/cow.png","http://"}
+\ShowLuaExampleThree {url} {addscheme} {"www.pragma-ade.com/cow.png"}
+\ShowLuaExampleThree {url} {filename} {"http://www.pragma-ade.com/cow.png"}
+\ShowLuaExampleTwo {url} {query} {"a=b&c=d"}
+
+\stopsection
+
+\startsection[title=OS]
+
+\startsummary[title={[lua luatex] env setenv getenv}]
+
+In \CONTEXT\ normally you will use the resolver functions to deal with the
+environment and files. However, a more low level interface is still available.
+You can query and set environment variables with two functions. In addition there
+is the \type {env} table as interface to the environment. This threesome replaces
+the built in functions.
+
+\starttyping
+os.setenv(key,value)
+os.getenv(key)
+os.env[key]
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={[lua] execute}]
+
+There are several functions for running programs. One comes directly from \LUA,
+the otheres come with \LUATEX. All of them are are overloaded in \CONTEXT\ in
+order to get more control.
+
+\starttyping
+os.execute(...)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={[luatex] spawn exec}]
+
+Two other runners are:
+
+\starttyping
+os.spawn(...)
+os.exec (...)
+\stoptyping
+
+The \type {exec} variant will transfer control from the current process to the
+new one and not return to the current job. There is a more detailed explanation
+in the \LUATEX\ manual.
+
+\stopsummary
+
+\startsummary[title={resultof launch}]
+
+The following function runs the command and returns the result as string.
+Multiple lines are combined.
+
+\starttyping
+os.resultof(command)
+\stoptyping
+
+The next one launches a file assuming that the operating system knows
+what application to use.
+
+\starttyping
+os.launch(str)
+\stoptyping
+
+\stopsummary
+
+\startsummary[title={type name platform libsuffix binsuffix}]
+
+There are a couple of strings that reflect the current machinery: \type {type}
+returns either \type {windows} or \type {unix}. The variable \type {name} is more
+detailed: \type {windows}, \type {msdos}, \type {linux}, \type {macosx}, etc. If
+you also want the architecture you can consult \type {platform}.
+
+\starttyping
+local t = os.type
+local n = os.name
+local p = os.platform
+\stoptyping
+
+These three variables as well as the next two are used internally and normally
+they are not needed in your applications as most functions that matter are aware
+of what platform specific things they have to deal with.
+
+\starttyping
+local s = os.libsuffix
+local b = os.binsuffix
+\stoptyping
+
+These are string, not functions.
+
+\ShowLuaExampleFive {os} {type}
+\ShowLuaExampleFive {os} {name}
+\ShowLuaExampleFive {os} {platform}
+\ShowLuaExampleFive {os} {libsuffix}
+\ShowLuaExampleFive {os} {binsuffix}
+
+\stopsummary
+
+\startsummary[title={[lua] time}]
+
+The built in time function returns a number. The accuracy is
+implementation dependent and not that large.
+
+\ShowLuaExampleThree {os} {time} {}
+
+\stopsummary
+
+\startsummary[title={[luatex] times gettimeofday}]
+
+Although \LUA\ has a built in type {os.time} function, we normally will use the
+one provided by \LUATEX\ as it is more precise:
+
+\starttyping
+os.gettimeofday()
+\stoptyping
+
+There is also a more extensive variant:
+
+\starttyping
+os.times()
+\stoptyping
+
+This one is platform dependent and returns a table with \type {utime} (use time),
+\type {stime} (system time), \type {cutime} (children user time), and \type
+{cstime} (children system time).
+
+\stopsummary
+
+\ShowLuaExampleThree {os} {gettimeofday} {}
+\ShowLuaExampleTwo {os} {times} {}
+
+\startsummary[title={runtime}]
+
+More interesting is:
+
+\starttyping
+os.runtime()
+\stoptyping
+
+which returns the time spent in the application so far.
+
+\ShowLuaExampleThree {os} {runtime} {}
+
+Sometimes you need to add the timezone to a verbose time and the following
+function does that for you.
+
+\starttyping
+os.timezone(delta)
+\stoptyping
+
+\ShowLuaExampleThree {os} {timezone} {}
+\ShowLuaExampleThree {os} {timezone} {1}
+\ShowLuaExampleThree {os} {timezone} {-1}
+
+\stopsummary
+
+\startsummary[title={uuid}]
+
+A version 4 UUID can be generated with:
+
+\starttyping
+os.uuid()
+\stoptyping
+
+The generator is good enough for our purpose.
+
+\ShowLuaExampleThree {os} {uuid} {}
+
+\stopsummary
+
+\stopsection
+
+\stopchapter
+
+\stopcomponent