luahtml: added UTF-8-to-form encoder written in C; Markup, Debug: minor fixes
authorTimm S. Mueller <tmueller@neoscientists.org>
Fri, 12 Sep 2008 22:00:42 +0200
changeset 2443a4291950c9f
parent 243 ae976ed38923
child 245 c2fd74f770ef
luahtml: added UTF-8-to-form encoder written in C; Markup, Debug: minor fixes
and new debugging features merged back in from other projects; FastCGI
launcher: no longer enforces full garbage collection
cgi-bin/loona_fastcgi.lua
cgi-bin/tek/class/markup.lua
cgi-bin/tek/lib/debug.lua
cgi-bin/tek/lib/luahtml.c
     1.1 --- a/cgi-bin/loona_fastcgi.lua	Mon Jun 30 02:11:03 2008 +0200
     1.2 +++ b/cgi-bin/loona_fastcgi.lua	Fri Sep 12 22:00:42 2008 +0200
     1.3 @@ -131,19 +131,17 @@
     1.4  -- Run:
     1.5  
     1.6  while true do
     1.7 +	collectgarbage("step")
     1.8  	local client, msg = app.server:accept()
     1.9  	if client then
    1.10  		local t0 = socket.gettime()
    1.11 -		local mem0 = collectgarbage("count")
    1.12  		FCGIServer:new { userdata = app }:serve(client)
    1.13  		client:close()
    1.14 -		local mem1 = collectgarbage("count")
    1.15 -		collectgarbage("collect")
    1.16 +		local mem = collectgarbage("count")
    1.17  		local t1 = socket.gettime()
    1.18  		local t = t1 - t0
    1.19  		local d = os.date("*t", t1)
    1.20 -		db.info("%04d-%02d-%02d %02d:%02d:%02d - Mem used: %.1fk - for request: %.1fk - elapsed: %.2fs",
    1.21 -			d.year, d.month, d.day, d.hour, d.min, d.sec,
    1.22 -			mem1, mem1 - mem0, t)
    1.23 +		db.info("%04d-%02d-%02d %02d:%02d:%02d - Mem used: %.1fk - elapsed: %.2fs",
    1.24 +			d.year, d.month, d.day, d.hour, d.min, d.sec, mem, t)
    1.25  	end
    1.26  end
     2.1 --- a/cgi-bin/tek/class/markup.lua	Mon Jun 30 02:11:03 2008 +0200
     2.2 +++ b/cgi-bin/tek/class/markup.lua	Fri Sep 12 22:00:42 2008 +0200
     2.3 @@ -4,11 +4,14 @@
     2.4  --	Written by Timm S. Mueller <tmueller at schulze-mueller.de>
     2.5  --	See copyright notice in COPYRIGHT
     2.6  --
     2.7 +--	LINEAGE::
     2.8 +--		[[#ClassOverview]] :
     2.9 +--		[[#tek.class : Class]] /
    2.10 +--		Markup
    2.11 +--
    2.12  --	OVERVIEW::
    2.13 ---		[[#ClassOverview : Lineage]] :
    2.14 ---		[[#tek.class : Class]] /
    2.15 ---		Markup - Markup parser producing fancy HTML from plain text with
    2.16 ---		special formattings
    2.17 +--		This class impelements a parser for producing feature-rich
    2.18 +--		XHTML 1.0 from plain text with special formattings.
    2.19  --
    2.20  --	FUNCTIONS::
    2.21  --	- Markup:new()
    2.22 @@ -89,7 +92,7 @@
    2.23  --				- san
    2.24  --			* drei
    2.25  --
    2.26 ---	'''NOTE''': Although not striclty required, it is recommended to
    2.27 +--	'''NOTE''': Although not strictly required, it is recommended to
    2.28  --	indent lists by one level. This will help the parser to avoid
    2.29  --	ambiguities; otherwise, when a regular block follows an unindented
    2.30  --	list, it would be concatenated with the last item, as empty lines are
    2.31 @@ -97,7 +100,9 @@
    2.32  --
    2.33  --	=== Links ===
    2.34  --
    2.35 ---	Links are enclosed in double squared brackets:
    2.36 +--	Links are enclosed in double squared brackets, according to the
    2.37 +--	template {{[[description][link target]]}}, where {{[description]}}
    2.38 +--	is optional, e.g.:
    2.39  --
    2.40  --		* [[home]] -
    2.41  --		Internal link: Link target is description at the same time.
    2.42 @@ -162,19 +167,23 @@
    2.43  --
    2.44  --	=== Nodes ===
    2.45  --
    2.46 +--	The possible templates for nodes are
    2.47 +--		- {{==( link target )==}}
    2.48 +--		- {{==( link target : description )==}}
    2.49  --	''Nodes'' translate to anchors in a document, and a browser will
    2.50  --	usually interprete them as jump targets. Visually, nodes translate
    2.51  --	to headlines also; as usual, the number of equal signs with which
    2.52  --	the heading is paired determines the significance and therefore
    2.53 ---	size of a headline:
    2.54 +--	size of a headline, e.g.:
    2.55  --
    2.56  --		=( Large )=
    2.57  --		==( Medium )==
    2.58  --		===( Small : Small node with alternate text )===
    2.59  --
    2.60  --	In addition to normal node headlines, there is also a variant which
    2.61 ---	is marked up as code. This is especially useful for jump targets in
    2.62 ---	technical documentation:
    2.63 +--	is marked up as code, which is indicated by braces instead of
    2.64 +--	parantheses. This is especially useful for jump targets in technical
    2.65 +--	documentation:
    2.66  --
    2.67  --		={ LargeCode : Large code node }=
    2.68  --		=={ MediumCode : Medium code node }==
    2.69 @@ -202,10 +211,11 @@
    2.70  local stdin = io.stdin
    2.71  local stdout = io.stdout
    2.72  local ipairs = ipairs
    2.73 +local have_luahtml, luahtml = pcall(require, "tek.lib.luahtml")
    2.74  
    2.75  module("tek.class.markup", tek.class)
    2.76  
    2.77 -_VERSION = "Markup 2.5"
    2.78 +_VERSION = "Markup 2.8"
    2.79  local Markup = _M
    2.80  
    2.81  -------------------------------------------------------------------------------
    2.82 @@ -325,31 +335,37 @@
    2.83  --	encodeform: encode for forms (display '<', '>', '&', '"' literally)
    2.84  -------------------------------------------------------------------------------
    2.85  
    2.86 -function Markup:encodeform(s)
    2.87 -	local tab = { }
    2.88 -	if s then
    2.89 -		for c in utf8values(s) do
    2.90 -			if c == 34 then
    2.91 -				insert(tab, "&quot;")
    2.92 -			elseif c == 38 then
    2.93 -				insert(tab, "&amp;")
    2.94 -			elseif c == 60 then
    2.95 -				insert(tab, "&lt;")
    2.96 -			elseif c == 62 then
    2.97 -				insert(tab, "&gt;")
    2.98 -			elseif c == 91 or c == 93 or c > 126 then
    2.99 -				insert(tab, ("&#%03d;"):format(c))
   2.100 -			else
   2.101 -				insert(tab, char(c))
   2.102 +if have_luahtml then
   2.103 +	function Markup:encodeform(s)
   2.104 +		return luahtml.encodeform(s)
   2.105 +	end
   2.106 +else
   2.107 +	function Markup:encodeform(s)
   2.108 +		local tab = { }
   2.109 +		if s then
   2.110 +			for c in utf8values(s) do
   2.111 +				if c == 34 then
   2.112 +					insert(tab, "&quot;")
   2.113 +				elseif c == 38 then
   2.114 +					insert(tab, "&amp;")
   2.115 +				elseif c == 60 then
   2.116 +					insert(tab, "&lt;")
   2.117 +				elseif c == 62 then
   2.118 +					insert(tab, "&gt;")
   2.119 +				elseif c == 91 or c == 93 or c > 126 then
   2.120 +					insert(tab, ("&#%03d;"):format(c))
   2.121 +				else
   2.122 +					insert(tab, char(c))
   2.123 +				end
   2.124  			end
   2.125  		end
   2.126 +		return concat(tab)
   2.127  	end
   2.128 -	return concat(tab)
   2.129  end
   2.130  
   2.131  -------------------------------------------------------------------------------
   2.132  --	encodeurl: encode string to url; optionally specify a string with a
   2.133 ---	set of characters that should be excluded from encoding, from: $&+,/:;=?@
   2.134 +--	set of characters that should be left unmodified, from: $&+,/:;=?@
   2.135  -------------------------------------------------------------------------------
   2.136  
   2.137  local function encodefunc(c)
   2.138 @@ -382,7 +398,7 @@
   2.139  				insert(tab, 1, ("\t"):rep(self.depth))
   2.140  			end
   2.141  			self.inline = true
   2.142 -			self.brpend = nil
   2.143 +			self.brpend = false
   2.144  		else
   2.145  			if id == "image" then
   2.146  				if not self.inline then
   2.147 @@ -391,7 +407,7 @@
   2.148  				self.brpend = true
   2.149  			else
   2.150  				if id == "pre" or id == "preline" then
   2.151 -					self.brpend = nil
   2.152 +					self.brpend = false
   2.153  				elseif open or id ~= "preline" then
   2.154  					insert(tab, 1, ("\t"):rep(self.depth))
   2.155  					if not open and self.inline then
   2.156 @@ -404,8 +420,8 @@
   2.157  				if id ~= "preline" or not open then
   2.158  					insert(tab, "\n")
   2.159  				end
   2.160 -				self.inline = nil
   2.161 -				self.brpend = nil
   2.162 +				self.inline = false
   2.163 +				self.brpend = false
   2.164  			end
   2.165  		end
   2.166  		return concat(tab)
   2.167 @@ -502,7 +518,7 @@
   2.168  end
   2.169  
   2.170  function Markup:def(name)
   2.171 -	self.prebr = nil
   2.172 +	self.prebr = false
   2.173  	return '<div class="definition"><dfn>' .. name .. '</dfn>', '</div>'
   2.174  end
   2.175  
   2.176 @@ -554,7 +570,7 @@
   2.177  		return '<a href="#' .. func .. '"><code>', '</code></a>'
   2.178  	else
   2.179  		local url, anch = link:match("^([^#]*#?)([^#]*)$")
   2.180 -		link = url .. anch:gsub("[^a-zA-Z%_%-%.%:]", "")
   2.181 +		link = url .. anch:gsub("[^a-zA-Z%d%_%-%.%:]", "")
   2.182  		return '<a href="' .. link .. '">', '</a>'
   2.183  	end
   2.184  end
   2.185 @@ -578,6 +594,9 @@
   2.186  		(extra or "") .. ' alt="image" />'
   2.187  end
   2.188  
   2.189 +function Markup:document()
   2.190 +end
   2.191 +
   2.192  -------------------------------------------------------------------------------
   2.193  --	run: Runs the parser
   2.194  -------------------------------------------------------------------------------
   2.195 @@ -687,7 +706,7 @@
   2.196  	end
   2.197  
   2.198  	local function popfragment()
   2.199 -		self.context.firstfragment = nil
   2.200 +		self.context.firstfragment = false
   2.201  		local frag = remove(self.context.fragments, 1)
   2.202  		if frag then
   2.203  			self.line = frag.line
   2.204 @@ -695,7 +714,7 @@
   2.205  				self.context.firstfragment = self.context.parentfirstfragment
   2.206  			end
   2.207  		else
   2.208 -			self.line = nil
   2.209 +			self.line = false
   2.210  		end
   2.211  		return self.line
   2.212  	end
   2.213 @@ -710,7 +729,7 @@
   2.214  	end
   2.215  
   2.216  	local function popcontext()
   2.217 -		self.context = remove(self.cstack)
   2.218 +		self.context = remove(self.cstack) or false
   2.219  		return self.context
   2.220  	end
   2.221  
   2.222 @@ -720,9 +739,9 @@
   2.223  	self.previndent = 0
   2.224  	self.stack = { }
   2.225  	self.depth = 0
   2.226 -	self.in_table = nil
   2.227 -	self.prebr = nil
   2.228 -	self.is_dynamic_content = nil
   2.229 +	self.in_table = false
   2.230 +	self.prebr = false
   2.231 +	self.is_dynamic_content = false
   2.232  
   2.233  	doout("init", self.docname)
   2.234  	push("document")
   2.235 @@ -747,7 +766,7 @@
   2.236  		end)
   2.237  
   2.238  		if feature["t"] then
   2.239 -			self.istabline = line:find("||", 1, 1)
   2.240 +			self.istabline = line:find("||", 1, 1) or false
   2.241  			if self.istabline then
   2.242  				self.indentlevel = self.previndent
   2.243  			end
   2.244 @@ -755,7 +774,7 @@
   2.245  				popuntil("row")
   2.246  				if not self.istabline then
   2.247  					popuntil("table")
   2.248 -					self.in_table = nil
   2.249 +					self.in_table = false
   2.250  				end
   2.251  			end
   2.252  		end
   2.253 @@ -770,7 +789,7 @@
   2.254  					end
   2.255  					popuntil("indent", "pre")
   2.256  				end
   2.257 -				self.preindent = nil
   2.258 +				self.preindent = false
   2.259  			end
   2.260  		elseif self.indentlevel == self.previndent + 1 then
   2.261  			popif("block")
   2.262 @@ -873,7 +892,7 @@
   2.263  						push("preline")
   2.264  						doout("getpre", "")
   2.265  						pop()
   2.266 -						self.prepend = nil
   2.267 +						self.prepend = false
   2.268  					end
   2.269  
   2.270  					if line == "" then
   2.271 @@ -886,7 +905,7 @@
   2.272  					end
   2.273  
   2.274  				else
   2.275 -					self.prepend = nil
   2.276 +					self.prepend = false
   2.277  
   2.278  					if line ~= "" then
   2.279  
   2.280 @@ -1133,5 +1152,26 @@
   2.281  	self.wrfunc = self.wrfunc or function(s) stdout:write(s) end
   2.282  	self.features = self.features or "hespcadlint"
   2.283  	self.docname = self.docname or "Manual"
   2.284 +
   2.285 +	self.column = false
   2.286 +	self.inline = false
   2.287 +	self.brpend = false
   2.288 +	self.prepend = false
   2.289 +	self.line = false
   2.290 +	self.id = false
   2.291 +	self.cstack = false
   2.292 +	self.context = false
   2.293 +	self.lnr = false
   2.294 +	self.indentlevel = 0
   2.295 +	self.istabline = false
   2.296 +	self.preindent = false
   2.297 +	self.previndent = 0
   2.298 +	self.preline = false
   2.299 +	self.stack = { }
   2.300 +	self.depth = 0
   2.301 +	self.in_table = false
   2.302 +	self.prebr = false
   2.303 +	self.is_dynamic_content = false
   2.304 +
   2.305  	return Class.new(class, self)
   2.306  end
     3.1 --- a/cgi-bin/tek/lib/debug.lua	Mon Jun 30 02:11:03 2008 +0200
     3.2 +++ b/cgi-bin/tek/lib/debug.lua	Fri Sep 12 22:00:42 2008 +0200
     3.3 @@ -1,49 +1,73 @@
     3.4  -------------------------------------------------------------------------------
     3.5  --
     3.6  --	tek.lib.debug
     3.7 ---	Written by Timm S. Mueller <tmueller at neoscientists.org>
     3.8 +--	Written by Timm S. Mueller <tmueller at schulze-mueller.de>
     3.9  --	See copyright notice in COPYRIGHT
    3.10  --
    3.11  --	OVERVIEW::
    3.12  --	Debug library - implements debug output and debug levels:
    3.13  --
    3.14 ---	2  || trace || used for tracking bugs
    3.15 ---	4  || info  || informational messages during development
    3.16 ---	5  || warn  || something unexpected happened
    3.17 ---	10 || error || something went wrong, e.g. allocation of a resource
    3.18 ---	20 || fail  || something went wrong that the program can't cope with
    3.19 +--	2  || TRACE || used for tracking bugs
    3.20 +--	4  || INFO  || informational messages
    3.21 +--	5  || WARN  || something unexpected happened
    3.22 +--	10 || ERROR || something went wrong, e.g. resource unavailable
    3.23 +--	20 || FAIL  || something went wrong that can't be coped with
    3.24  --
    3.25 ---	The default debug level is 10 ''error''. To set the debug level
    3.26 +--	The default debug level is 10 {{ERROR}}. To set the debug level
    3.27  --	globally, e.g.:
    3.28  --			db = require "tek.lib.debug"
    3.29 ---			db.level = 4
    3.30 +--			db.level = db.INFO
    3.31  --
    3.32  --	The default debug output stream is {{stderr}}.
    3.33  --	To override it globally, e.g.:
    3.34  --			db = require "tek.lib.debug"
    3.35 ---			f = io.open("logfile", "w")
    3.36 ---			db.out = function(...) f:write(...) end
    3.37 +--			db.out = io.open("logfile", "w")
    3.38 +--
    3.39 +--	FUNCTIONS::
    3.40 +--		- debug.console() - Enter debug console
    3.41 +--		- debug.dump() - Dump a table recursively
    3.42 +--		- debug.error() - Print a text in the {{ERROR}} debug level
    3.43 +--		- debug.execute() - Execute a function in the specified debug level
    3.44 +--		- debug.fail() - Print a text in the {{FAIL}} debug level
    3.45 +--		- debug.info() - Print a text in the {{INFO}} debug level
    3.46 +--		- debug.print() - Print a text in the specified debug level
    3.47 +--		- debug.stacktrace() - Print a stacktrace in the specified debug level
    3.48 +--		- debug.trace() - Print a text in the {{TRACE}} debug level
    3.49 +--		- debug.warn() - Print a text in the {{WARN}} debug level
    3.50  --
    3.51  -------------------------------------------------------------------------------
    3.52  
    3.53 -local getinfo = require "debug".getinfo
    3.54 -local stderr = require "io".stderr
    3.55 +local debug = require "debug"
    3.56 +local getinfo = debug.getinfo
    3.57 +local stderr = io.stderr
    3.58 +local pairs = pairs
    3.59 +local select = select
    3.60 +local time = os.time
    3.61 +local tonumber = tonumber
    3.62  local tostring = tostring
    3.63 -local tonumber = tonumber
    3.64 +local traceback = debug.traceback
    3.65  local type = type
    3.66  local unpack = unpack
    3.67 -local select = select
    3.68 -local time = os.time
    3.69  
    3.70  module "tek.lib.debug"
    3.71 -_VERSION = "Debug 1.1"
    3.72 +_VERSION = "Debug 4.0"
    3.73 +
    3.74 +-- symbolic:
    3.75 +
    3.76 +TRACE = 2
    3.77 +INFO = 4
    3.78 +WARN = 5
    3.79 +ERROR = 10
    3.80 +FAIL = 20
    3.81  
    3.82  -- global defaults:
    3.83 -level = 10
    3.84 -out = function(...) stderr:write(...) end
    3.85 +
    3.86 +level = ERROR
    3.87 +out = stderr
    3.88 +wrout = function(...) out:write(...) end
    3.89  
    3.90  -------------------------------------------------------------------------------
    3.91 ---	print(lvl, msg, ...): prints formatted text if the global debug level
    3.92 +--	print(lvl, msg, ...): Prints formatted text if the global debug level
    3.93  --	is less or equal the specified level.
    3.94  -------------------------------------------------------------------------------
    3.95  
    3.96 @@ -55,13 +79,13 @@
    3.97  			local v = select(i, ...)
    3.98  			arg[i] = v and type(v) ~= "number" and tostring(v) or v or 0
    3.99  		end
   3.100 -		out(("(%02d %d %s:%d) " .. msg):format(lvl,
   3.101 +		wrout(("(%02d %d %s:%d) " .. msg):format(lvl,
   3.102  			time(), t.short_src, t.currentline, unpack(arg)) .. "\n")
   3.103  	end
   3.104  end
   3.105  
   3.106  -------------------------------------------------------------------------------
   3.107 ---	execute(lvl, func, ...): executes the specified function if the global
   3.108 +--	execute(lvl, func, ...): Executes the specified function if the global
   3.109  --	debug library is less or equal the specified level.
   3.110  -------------------------------------------------------------------------------
   3.111  
   3.112 @@ -72,32 +96,84 @@
   3.113  end
   3.114  
   3.115  -------------------------------------------------------------------------------
   3.116 ---	trace(msg, ...): prints formatted debug info with ''trace'' level
   3.117 +--	trace(msg, ...): Prints formatted debug info with {{TRACE}} level
   3.118  -------------------------------------------------------------------------------
   3.119  function trace(msg, ...) print(2, msg, ...) end
   3.120  
   3.121  -------------------------------------------------------------------------------
   3.122 ---	info(msg, ...): prints formatted debug info with ''info'' level
   3.123 +--	info(msg, ...): Prints formatted debug info with {{INFO}} level
   3.124  -------------------------------------------------------------------------------
   3.125  function info(msg, ...) print(4, msg, ...) end
   3.126  
   3.127  -------------------------------------------------------------------------------
   3.128 ---	warn(msg, ...): prints formatted debug info with ''warn'' level
   3.129 +--	warn(msg, ...): Prints formatted debug info with {{WARN}} level
   3.130  -------------------------------------------------------------------------------
   3.131  function warn(msg, ...) print(5, msg, ...) end
   3.132  
   3.133  -------------------------------------------------------------------------------
   3.134 ---	error(msg, ...): prints formatted debug info with ''error'' level
   3.135 +--	error(msg, ...): Prints formatted debug info with {{ERROR}} level
   3.136  -------------------------------------------------------------------------------
   3.137  function error(msg, ...) print(10, msg, ...) end
   3.138  
   3.139  -------------------------------------------------------------------------------
   3.140 ---	fail(msg, ...): prints formatted debug info with ''fail'' level
   3.141 +--	fail(msg, ...): Prints formatted debug info with {{FAIL}} level
   3.142  -------------------------------------------------------------------------------
   3.143  function fail(msg, ...) print(20, msg, ...) end
   3.144  
   3.145 -function dotrace(msg, ...) execute(2, msg, ...) end
   3.146 -function doinfo(msg, ...) execute(4, msg, ...) end
   3.147 -function dowarn(msg, ...) execute(5, msg, ...) end
   3.148 -function doerror(msg, ...) execute(10, msg, ...) end
   3.149 -function dofail(msg, ...) execute(20, msg, ...) end
   3.150 +-------------------------------------------------------------------------------
   3.151 +--	stacktrace(debuglevel, stacklevel): Prints a stacktrace starting at
   3.152 +--	the function of the given {{level}} on the stack (excluding the
   3.153 +--	{{stracktrace}} function itself) if the global debug level is less
   3.154 +--	or equal the specified {{debuglevel}}.
   3.155 +-------------------------------------------------------------------------------
   3.156 +
   3.157 +function stacktrace(lvl, level)
   3.158 +	print(lvl, traceback("", level or 1 + 1))
   3.159 +end
   3.160 +
   3.161 +-------------------------------------------------------------------------------
   3.162 +--	console(): Enter the debug console.
   3.163 +-------------------------------------------------------------------------------
   3.164 +
   3.165 +function console()
   3.166 +	stderr:write('Entering the debug console.\n')
   3.167 +	stderr:write('To redirect the output, e.g.:\n')
   3.168 +	stderr:write('  tek.lib.debug.out = io.open("logfile", "w")\n')
   3.169 +	stderr:write('To dump a table, e.g.:\n')
   3.170 +	stderr:write('  tek.lib.debug.dump("app", app)\n')
   3.171 +	stderr:write('Use "cont" to continue.\n')
   3.172 +	debug.debug()
   3.173 +end
   3.174 +
   3.175 +-------------------------------------------------------------------------------
   3.176 +--	dump(name, table): Dump a table
   3.177 +-------------------------------------------------------------------------------
   3.178 +
   3.179 +local function basicSerialize(o)
   3.180 +	if type(o) == "string" then
   3.181 +		return ("%q"):format(o)
   3.182 +	elseif type(o) == "userdata" then
   3.183 +		return "<userdata>"
   3.184 +	end
   3.185 +	return tostring(o)
   3.186 +end
   3.187 +
   3.188 +function dump(name, value, saved)
   3.189 +	saved = saved or {}       -- initial value
   3.190 +	wrout(name, " = ")
   3.191 +	local t = type(value)
   3.192 +	if t == "table" then
   3.193 +		if saved[value] then    -- value already saved?
   3.194 +			wrout(saved[value], "\n")
   3.195 +		else
   3.196 +			saved[value] = name   -- save name for next time
   3.197 +			wrout("{}\n")
   3.198 +			for k,v in pairs(value) do      -- save its fields
   3.199 +				local fieldname = ("%s[%s]"):format(name, basicSerialize(k))
   3.200 +				dump(fieldname, v, saved)
   3.201 +			end
   3.202 +		end
   3.203 +	else
   3.204 +		wrout(basicSerialize(value), "\n")
   3.205 +	end
   3.206 +end
     4.1 --- a/cgi-bin/tek/lib/luahtml.c	Mon Jun 30 02:11:03 2008 +0200
     4.2 +++ b/cgi-bin/tek/lib/luahtml.c	Fri Sep 12 22:00:42 2008 +0200
     4.3 @@ -79,6 +79,7 @@
     4.4  	void *udata;
     4.5  };
     4.6  
     4.7 +
     4.8  static int readstring(struct utf8reader *rd)
     4.9  {
    4.10  	if (rd->srclen == 0)
    4.11 @@ -87,11 +88,13 @@
    4.12  	return *rd->src++;
    4.13  }
    4.14  
    4.15 +
    4.16  static int readfile(struct utf8reader *rd)
    4.17  {
    4.18  	return fgetc(rd->file);
    4.19  }
    4.20  
    4.21 +
    4.22  static int readutf8(struct utf8reader *rd)
    4.23  {
    4.24  	int c;
    4.25 @@ -383,9 +386,72 @@
    4.26  }
    4.27  
    4.28  
    4.29 +/*****************************************************************************/
    4.30 +
    4.31 +
    4.32 +static int encodeform(lua_State *L)
    4.33 +{
    4.34 +	struct readdata rd;
    4.35 +	char sbuf[16];
    4.36 +	luaL_Buffer b;
    4.37 +	int c;
    4.38 +
    4.39 +	if (lua_isuserdata(L, 1))
    4.40 +	{
    4.41 +		rd.utf8.file = tofile(L);
    4.42 +		rd.utf8.readchar = readfile;
    4.43 +	}
    4.44 +	else
    4.45 +	{
    4.46 +		rd.utf8.src = (unsigned char *) lua_tolstring(L, 1, &rd.utf8.srclen);
    4.47 +		rd.utf8.readchar = readstring;
    4.48 +	}
    4.49 +
    4.50 +	luaL_buffinit(L, &b);
    4.51 +
    4.52 +	rd.utf8.accu = 0;
    4.53 +	rd.utf8.numa = 0;
    4.54 +	rd.utf8.bufc = -1;
    4.55 +
    4.56 +	while ((c = readutf8(&rd.utf8)) >= 0)
    4.57 +	{
    4.58 +		switch(c)
    4.59 +		{
    4.60 +			case 34:
    4.61 +				luaL_addlstring(&b, "&quot;", 6);
    4.62 +				break;
    4.63 +			case 38:
    4.64 +				luaL_addlstring(&b, "&amp;", 5);
    4.65 +				break;
    4.66 +			case 60:
    4.67 +				luaL_addlstring(&b, "&lt;", 4);
    4.68 +				break;
    4.69 +			case 62:
    4.70 +				luaL_addlstring(&b, "&gt;", 4);
    4.71 +				break;
    4.72 +			default:
    4.73 +				if (c == 91 || c == 93 || c > 126)
    4.74 +				{
    4.75 +					sprintf(sbuf, "&#%03d;", c);
    4.76 +					luaL_addstring(&b, sbuf);
    4.77 +				}
    4.78 +				else
    4.79 +					luaL_addchar(&b, c);
    4.80 +		}
    4.81 +	}
    4.82 +
    4.83 +	luaL_pushresult(&b);
    4.84 +	return 1;
    4.85 +}
    4.86 +
    4.87 +
    4.88 +/*****************************************************************************/
    4.89 +
    4.90 +
    4.91  static const luaL_Reg lib[] =
    4.92  {
    4.93  	{ "load", load },
    4.94 +	{ "encodeform", encodeform },
    4.95  	{ NULL, NULL }
    4.96  };
    4.97