wikicloth 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- h2. WikiCloth "!https://secure.travis-ci.org/nricciar/wikicloth.png!":http://travis-ci.org/nricciar/wikicloth
1
+ h1. WikiCloth "!https://secure.travis-ci.org/nricciar/wikicloth.png!":http://travis-ci.org/nricciar/wikicloth
2
2
 
3
3
  Ruby implementation of the MediaWiki markup language.
4
4
 
@@ -16,7 +16,7 @@ h2. Supports
16
16
  ** "Tables":https://github.com/nricciar/wikicloth/wiki/Tables
17
17
  ** Table of Contents [<code>__NOTOC__, __FORCETOC__, __TOC__</code>]
18
18
  * <code><code>,<nowiki>,<pre></code> (disable wiki markup)
19
- * <ref> and <references/> support
19
+ * <code><ref></code> and <code><references/></code> support
20
20
  * "html sanitization":https://github.com/nricciar/wikicloth/wiki/Html-Sanitization
21
21
 
22
22
  For more information about the MediaWiki markup see "http://www.mediawiki.org/wiki/Markup_spec":http://www.mediawiki.org/wiki/Markup_spec
@@ -62,7 +62,7 @@ Most features of WikiCloth can be overriden as needed...
62
62
 
63
63
  @wiki = WikiParser.new({
64
64
  :params => { "PAGENAME" => "Testing123" },
65
- :data => "{{hello|world}} From {{ PAGENAME }} -- [www.google.com]&quot;
65
+ :data => "{{hello|world}} From {{ PAGENAME }} -- [www.google.com]";
66
66
  })
67
67
 
68
68
  @wiki.to_html =>
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ require 'rubygems'
1
2
  require 'rake'
2
3
  require File.join(File.dirname(__FILE__),'init')
3
4
 
@@ -10,22 +11,29 @@ Rake::TestTask.new(:test) do |test|
10
11
  test.verbose = true
11
12
  end
12
13
 
13
- require 'rcov/rcovtask'
14
- Rcov::RcovTask.new do |test|
15
- test.libs << 'test'
16
- test.pattern = 'test/**/test_*.rb'
17
- test.verbose = true
14
+ if RUBY_VERSION =~ /^1\.9/
15
+ require 'simplecov'
16
+ desc "Code coverage detail"
17
+ task :simplecov do
18
+ ENV['COVERAGE'] = "true"
19
+ Rake::Task['spec'].execute
20
+ end
21
+ else
22
+ require 'rcov/rcovtask'
23
+ Rcov::RcovTask.new do |test|
24
+ test.libs << 'test'
25
+ test.pattern = 'test/**/test_*.rb'
26
+ test.verbose = true
27
+ end
18
28
  end
19
29
 
20
30
  task :default => :test
21
31
 
22
- require 'rake/rdoctask'
23
- Rake::RDocTask.new do |rdoc|
24
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
25
-
32
+ require 'rdoc/task'
33
+ RDoc::Task.new do |rdoc|
26
34
  rdoc.rdoc_dir = 'rdoc'
27
- rdoc.title = "wikicloth #{version}"
35
+ rdoc.title = "wikicloth #{WikiCloth::VERSION}"
28
36
  rdoc.rdoc_files.include('README*')
29
- rdoc.rdoc_files.include('LICENSE')
37
+ rdoc.rdoc_files.include('MIT-LICENSE')
30
38
  rdoc.rdoc_files.include('lib/**/*.rb')
31
39
  end
@@ -0,0 +1,24 @@
1
+ :de:
2
+ namespaces:
3
+ media: "Medium"
4
+ file: "Datei"
5
+ category: "Kategorie"
6
+ template: "Vorlage"
7
+ special: "Spezial"
8
+ talk: "Diskussion"
9
+ help: "Hilfe"
10
+
11
+ languages:
12
+ en: "Englisch"
13
+ de: "Deutsch"
14
+
15
+ behavior_switches:
16
+ notoc: "KEIN_INHALTSVERZEICHNIS"
17
+ toc: "INHALTSVERZEICHNIS"
18
+ forcetoc: "INHALTSVERZEICHNIS_ERZWINGEN"
19
+ noeditsection: "ABSCHNITTE_NICHT_BEARBEITEN"
20
+ editsection: "ABSCHNITTE_BEARBEITEN"
21
+
22
+ table of contents: "Inhaltsverzeichnis"
23
+ edit: "Bearbeiten"
24
+ edit section: "Abschnitt bearbeiten: %{name}"
@@ -0,0 +1,35 @@
1
+ en:
2
+ namespaces:
3
+ media: "Media"
4
+ file: "File,Image"
5
+ category: "Category"
6
+ special: "Special"
7
+ template: "Template"
8
+ talk: "Talk"
9
+ help: "Help"
10
+
11
+ languages:
12
+ en: "English"
13
+ de: "German"
14
+
15
+ behavior_switches:
16
+ notoc: "NOTOC"
17
+ toc: "TOC"
18
+ forcetoc: "FORCETOC"
19
+ noeditsection: "NOEDITSECTION"
20
+ editsection: "EDITSECTION"
21
+
22
+ table of contents: "Table of Contents"
23
+ edit: "edit"
24
+ edit section: "Edit section: %{name}"
25
+ template loop detected: "Template loop detected: &#123;&#123;%{tree}&#125;&#125;"
26
+ expression error: "Expression error: %{error}"
27
+ lang attribute is required: "lang attribute is required"
28
+ unknown lang: "unknown lang '%{lang}'"
29
+ unable to parse mathml: "Unable to parse MathML: %{error}"
30
+ blahtex binary not found: "%{path} binary not found"
31
+ unknown function: "unknown function '%{function}'"
32
+ lua disabled: "Lua extension not configured"
33
+ max lines of code: "Maximum lines of code limit reached"
34
+ recursion limit reached: "Recursion limit reached"
35
+ unknown error on line: "Unknown error on line %{line} row %{row}: %{tree}"
@@ -1,12 +1,20 @@
1
+ require 'rubygems' if RUBY_VERSION < '1.9'
1
2
  require 'jcode' if RUBY_VERSION < '1.9'
2
- require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "core_ext")
3
+ require 'builder'
4
+ # if i18n gem loaded use it instead
5
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "i18n") unless defined?(I18n)
6
+ I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) if defined?(I18n::Backend::Simple)
7
+ I18n.load_path += Dir[File.join(File.expand_path(File.dirname(__FILE__)), "../lang/*.yml")].collect { |f| f }
8
+
3
9
  require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "version")
10
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "core_ext")
11
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "namespaces")
12
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "extension")
13
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "section")
4
14
  require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "wiki_buffer")
5
15
  require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "wiki_link_handler")
6
16
  require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "parser")
7
- require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "section")
8
- require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "token")
9
- require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "lexer")
17
+
10
18
  String.send(:include, ExtendedString)
11
19
 
12
20
  module WikiCloth
@@ -14,6 +22,8 @@ module WikiCloth
14
22
  class WikiCloth
15
23
 
16
24
  def initialize(opt={})
25
+ self.options.merge!(opt)
26
+ self.options[:extensions] ||= []
17
27
  self.options[:link_handler] = opt[:link_handler] unless opt[:link_handler].nil?
18
28
  self.load(opt[:data],opt[:params]) unless opt[:data].nil?
19
29
  @current_line = 1
@@ -49,15 +59,13 @@ module WikiCloth
49
59
  self.params = p
50
60
  end
51
61
 
52
- def sections
53
- @sections ||= [Section.new]
54
- end
55
-
56
62
  def render(opt={})
57
- noedit = false
58
- self.params.merge!({ 'WIKI_VERSION' => ::WikiCloth::VERSION, 'RUBY_VERSION' => RUBY_VERSION })
59
- self.options = { :fast => true, :output => :html, :link_handler => self.link_handler, :params => self.params, :sections => self.sections }.merge(opt)
63
+ self.options = { :noedit => false, :locale => I18n.default_locale, :fast => true, :output => :html, :link_handler => self.link_handler,
64
+ :params => self.params, :sections => self.sections }.merge(self.options).merge(opt)
60
65
  self.options[:link_handler].params = options[:params]
66
+
67
+ I18n.locale = self.options[:locale]
68
+
61
69
  data = self.sections.collect { |s| s.render(self.options) }.join
62
70
  data.gsub!(/<!--(.|\s)*?-->/,"")
63
71
  data << "\n" if data.last(1) != "\n"
@@ -83,25 +91,20 @@ module WikiCloth
83
91
  end
84
92
  rescue => err
85
93
  debug_tree = buffer.buffers.collect { |b| b.debug }.join("-->")
86
- puts "Unknown error on line #{@current_line} row #{@current_row}: #{debug_tree}"
94
+ puts I18n.t("unknown error on line", :line => @current_line, :row => @current_row, :tree => debug_tree)
87
95
  raise err
88
96
  end
89
97
 
90
98
  buffer.eof()
91
- buffer.to_s
99
+ buffer.send("to_#{self.options[:output]}")
92
100
  end
93
101
 
94
- def add_current_char(buffer,c)
95
- if c == "\n"
96
- @current_line += 1
97
- @current_row = 1
98
- else
99
- @current_row += 1
100
- end
101
- buffer.add_char(c)
102
+ def sections
103
+ @sections ||= [Section.new]
102
104
  end
105
+
103
106
  def to_html(opt={})
104
- self.render(opt)
107
+ self.render(opt.merge(:output => :html))
105
108
  end
106
109
 
107
110
  def link_handler
@@ -112,7 +115,29 @@ module WikiCloth
112
115
  @page_params ||= {}
113
116
  end
114
117
 
118
+ def options
119
+ @options ||= {}
120
+ end
121
+
122
+ def method_missing(method, *args)
123
+ if self.link_handler.respond_to?(method)
124
+ self.link_handler.send(method, *args)
125
+ else
126
+ super(method, *args)
127
+ end
128
+ end
129
+
115
130
  protected
131
+ def add_current_char(buffer,c)
132
+ if c == "\n"
133
+ @current_line += 1
134
+ @current_row = 1
135
+ else
136
+ @current_row += 1
137
+ end
138
+ buffer.add_char(c)
139
+ end
140
+
116
141
  def sections=(val)
117
142
  @sections = val
118
143
  end
@@ -129,10 +154,6 @@ module WikiCloth
129
154
  @options = val
130
155
  end
131
156
 
132
- def options
133
- @options ||= {}
134
- end
135
-
136
157
  def params=(val)
137
158
  @page_params = val
138
159
  end
@@ -38,6 +38,10 @@ module ExtendedString
38
38
  respond_to?(:empty?) ? empty? : !self
39
39
  end
40
40
 
41
+ def addslashes
42
+ self.gsub(/['"\\\x0]/,'\\\\\0');
43
+ end
44
+
41
45
  def to_slug
42
46
  self.gsub(/\W+/, '-').gsub(/^-+/,'').gsub(/-+$/,'').downcase
43
47
  end
@@ -0,0 +1,60 @@
1
+ module WikiCloth
2
+ class Extension
3
+
4
+ def initialize(options={})
5
+ @options = options
6
+ end
7
+
8
+ class << self
9
+
10
+ def html_elements
11
+ @@html_elements ||= {}
12
+ end
13
+
14
+ def functions
15
+ @@functions ||= {}
16
+ end
17
+
18
+ def element(*args,&block)
19
+ options = args.last.is_a?(Hash) ? args.pop : {}
20
+ key = args.shift
21
+
22
+ html_elements[key] = { :klass => self, :block => block, :options => {
23
+ :skip_html => false, :run_globals => true }.merge(options) }
24
+ end
25
+
26
+ def skip_html?(elem)
27
+ return true if !element_exists?(elem)
28
+ html_elements[elem][:options][:skip_html]
29
+ end
30
+
31
+ def run_globals?(elem)
32
+ return false if !element_exists?(elem)
33
+ html_elements[elem][:options][:run_globals]
34
+ end
35
+
36
+ def element_exists?(elem)
37
+ html_elements.has_key?(elem)
38
+ end
39
+
40
+ def function(name,&block)
41
+ functions[name] = { :klass => self, :block => block }
42
+ end
43
+
44
+ def function_exists?(name)
45
+ functions.has_key?(name)
46
+ end
47
+
48
+ protected
49
+ def html_elements=(val)
50
+ @@html_elements = val
51
+ end
52
+
53
+ def functions=(val)
54
+ @@functions = val
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,82 @@
1
+ begin
2
+ require 'rubyluabridge'
3
+ DISABLE_LUA = false
4
+ rescue LoadError
5
+ DISABLE_LUA = true
6
+ end
7
+
8
+ module WikiCloth
9
+ class LuaExtension < Extension
10
+
11
+ # <lua var1="value" ...>lua code</lua>
12
+ #
13
+ element 'lua', :skip_html => true, :run_globals => false do |buffer|
14
+ init_lua
15
+ unless @options[:disable_lua]
16
+ begin
17
+ arglist = ''
18
+ buffer.element_attributes.each do |key,value|
19
+ arglist += "#{key} = '#{value.addslashes}';"
20
+ end
21
+ lua_eval("#{arglist}\n#{buffer.element_content}").to_s
22
+ rescue => err
23
+ "<span class=\"error\">#{err.message}</span>"
24
+ end
25
+ else
26
+ "<!-- #{I18n.t('lua disabled')} -->"
27
+ end
28
+ end
29
+
30
+ # {{#luaexpr:lua expression}}
31
+ #
32
+ function '#luaexpr' do |params|
33
+ init_lua
34
+ unless @options[:disable_lua]
35
+ begin
36
+ lua_eval("print(#{params.first})").to_s
37
+ rescue => err
38
+ "<span class=\"error\">#{err.message}</span>"
39
+ end
40
+ else
41
+ "<!-- #{I18n.t('lua disabled')} -->"
42
+ end
43
+ end
44
+
45
+ protected
46
+ def init_lua
47
+ if @options[:disable_lua].nil?
48
+ begin
49
+ @options[:disable_lua] ||= DISABLE_LUA
50
+ lua_max_lines = @options[:lua_max_lines] || 1000000
51
+ lua_max_calls = @options[:lua_max_calls] || 20000
52
+
53
+ unless @options[:disable_lua]
54
+ @options[:luabridge] = Lua::State.new
55
+ @options[:luabridge].eval(File.read(File.join(File.expand_path(File.dirname(__FILE__)), "lua", "luawrapper.lua")))
56
+ @options[:luabridge].eval("wrap = make_wrapper(#{lua_max_lines},#{lua_max_calls})")
57
+ end
58
+ rescue
59
+ @options[:disable_lua] = true
60
+ end
61
+ end
62
+ end
63
+
64
+ def lua_eval(code)
65
+ @options[:luabridge]['chunkstr'] = code
66
+ @options[:luabridge].eval("res, err = wrap(chunkstr, env, hook)")
67
+ unless @options[:luabridge]['err'].nil?
68
+ if @options[:luabridge]['err'] =~ /LOC_LIMIT/
69
+ "<span class=\"error\">#{I18n.t("max lines of code")}</span>"
70
+ elsif @options[:luabridge]['err'] =~ /RECURSION_LIMIT/
71
+ "<span class=\"error\">#{I18n.t("recursion limit reached")}</span>"
72
+ else
73
+ "<span class=\"error\">#{@options[:luabridge]['err']}</span>"
74
+ end
75
+ nil
76
+ else
77
+ @options[:luabridge]['res']
78
+ end
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,18 @@
1
+ Lua parser extensions for MediaWiki
2
+ Copyright (C) 2008 Fran Rogers
3
+
4
+ This software is provided 'as-is', without any express or implied
5
+ warranty. In no event will the authors be held liable for any damages
6
+ arising from the use of this software.
7
+
8
+ Permission is granted to anyone to use this software for any purpose,
9
+ including commercial applications, and to alter it and redistribute it
10
+ freely, subject to the following restrictions:
11
+
12
+ 1. The origin of this software must not be misrepresented; you must not
13
+ claim that you wrote the original software. If you use this software
14
+ in a product, an acknowledgment in the product documentation would be
15
+ appreciated but is not required.
16
+ 2. Altered source versions must be plainly marked as such, and must not be
17
+ misrepresented as being the original software.
18
+ 3. This notice may not be removed or altered from any source distribution.
@@ -0,0 +1,245 @@
1
+ -- Lua parser extensions for MediaWiki - Wrapper for Lua interpreter
2
+ -- (c) 2008 Fran Rogers - see 'COPYING' for license
3
+
4
+ -- Creates a new sandbox environment for scripts to safely run in.
5
+ function make_sandbox()
6
+ -- Dummy function that returns nil, to quietly replace unsafe functions
7
+ local function dummy(...)
8
+ return nil
9
+ end
10
+
11
+ -- Deep-copy an object; optionally replace all its leaf members with the
12
+ -- value 'override' if it's non-nil
13
+ local function deepcopy(object, override)
14
+ local lookup_table = {}
15
+ local function _copy(object, override)
16
+ if type(object) ~= "table" then
17
+ return object
18
+ elseif lookup_table[object] then
19
+ return lookup_table[object]
20
+ end
21
+ local new_table = {}
22
+ lookup_table[object] = new_table
23
+ for index, value in pairs(object) do
24
+ if override ~= nil then
25
+ value = override
26
+ end
27
+ new_table[_copy(index)] = _copy(value, override)
28
+ end
29
+ return setmetatable(new_table, _copy(getmetatable(object), override))
30
+ end
31
+ return _copy(object, override)
32
+ end
33
+
34
+ -- Our new environment
35
+ local env = {}
36
+
37
+ -- "_OUTPUT" will accumulate the results of print() and friends
38
+ env._OUTPUT = ""
39
+
40
+ -- _OUTPUT wrapper for io.write()
41
+ local function writewrapper(...)
42
+ local out = ""
43
+ for n = 1, select("#", ...) do
44
+ if out == "" then
45
+ out = tostring(select(n, ...))
46
+ else
47
+ out = out .. tostring(select(n, ...))
48
+ end
49
+ end
50
+ env._OUTPUT = env._OUTPUT .. out
51
+ end
52
+
53
+ -- _OUTPUT wrapper for io.stdout:output()
54
+ local function outputwrapper(file)
55
+ if file == nil then
56
+ local file = {}
57
+ file.close = dummy
58
+ file.lines = dummy
59
+ file.read = dummy
60
+ file.flush = dummy
61
+ file.seek = dummy
62
+ file.setvbuf = dummy
63
+ function file:write(...) writewrapper(...); end
64
+ return file
65
+ else
66
+ return nil
67
+ end
68
+ end
69
+
70
+ -- _OUTPUT wrapper for print()
71
+ local function printwrapper(...)
72
+ local out = ""
73
+ for n = 1, select("#", ...) do
74
+ if out == "" then
75
+ out = tostring(select(n, ...))
76
+ else
77
+ out = out .. '\t' .. tostring(select(n, ...))
78
+ end
79
+ end
80
+ env._OUTPUT =env._OUTPUT .. out .. "\n"
81
+ end
82
+
83
+ -- Safe wrapper for loadstring()
84
+ local oldloadstring = loadstring
85
+ local function safeloadstring(s, chunkname)
86
+ local f, message = oldloadstring(s, chunkname)
87
+ if not f then
88
+ return f, message
89
+ end
90
+ setfenv(f, getfenv(2))
91
+ return f
92
+ end
93
+
94
+ -- Populate the sandbox environment
95
+ env.assert = _G.assert
96
+ env.error = _G.error
97
+ env._G = env
98
+ env.ipairs = _G.ipairs
99
+ env.loadstring = safeloadstring
100
+ env.next = _G.next
101
+ env.pairs = _G.pairs
102
+ env.pcall = _G.pcall
103
+ env.print = printwrapper
104
+ env.write = writewrapper
105
+ env.select = _G.select
106
+ env.tonumber = _G.tonumber
107
+ env.tostring = _G.tostring
108
+ env.type = _G.type
109
+ env.unpack = _G.unpack
110
+ env._VERSION = _G._VERSION
111
+ env.xpcall = _G.xpcall
112
+ env.coroutine = deepcopy(_G.coroutine)
113
+ env.string = deepcopy(_G.string)
114
+ env.string.dump = nil
115
+ env.table = deepcopy(_G.table)
116
+ env.math = deepcopy(_G.math)
117
+ env.io = {}
118
+ env.io.write = writewrapper
119
+ env.io.flush = dummy
120
+ env.io.type = typewrapper
121
+ env.io.output = outputwrapper
122
+ env.io.stdout = outputwrapper()
123
+ env.os = {}
124
+ env.os.clock = _G.os.clock
125
+ -- env.os.date = _G.os.date
126
+ env.os.difftime = _G.os.difftime
127
+ env.os.time = _G.os.time
128
+
129
+ -- Return the new sandbox environment
130
+ return env
131
+ end
132
+
133
+ -- Creates a new debug hook that aborts with 'error("LOC_LIMIT")' after
134
+ -- 'maxlines' lines have been passed, or 'error("RECURSION_LIMIT")' after
135
+ -- 'maxcalls' levels of recursion have been entered.
136
+ function make_hook(maxlines, maxcalls, diefunc)
137
+ local lines = 0
138
+ local calls = 0
139
+ function _hook(event, ...)
140
+ if event == "line" then
141
+ lines = lines + 1
142
+ if lines > maxlines then
143
+ error("LOC_LIMIT")
144
+ end
145
+ elseif event == "call" then
146
+ calls = calls + 1
147
+ if calls > maxcalls then
148
+ error("RECURSION_LIMIT")
149
+ end
150
+ elseif event == "return" then
151
+ calls = calls - 1
152
+ end
153
+ end
154
+ return _hook
155
+ end
156
+
157
+ -- Creates and returns a function, 'wrap(input)', which reads a string into
158
+ -- a Lua chunk and executes it in a persistent sandbox environment, returning
159
+ -- 'output, err' where 'output' is the combined output of print() and friends
160
+ -- from within the chunk and 'err' is either nil or an error incurred while
161
+ -- executing the chunk; or halting after 'maxlines' lines or 'maxcalls' levels
162
+ -- of recursion.
163
+ function make_wrapper(maxlines, maxcalls)
164
+ -- Create the debug hook and sandbox environment.
165
+ local hook = make_hook(maxlines, maxcalls)
166
+ local env = make_sandbox()
167
+
168
+ -- The actual 'wrap()' function.
169
+ -- All of the above variables will be bound in its closure.
170
+ function _wrap(chunkstr)
171
+ local chunk, err, done
172
+ -- Clear any leftover output from the last call
173
+ env._OUTPUT = ""
174
+ err = nil
175
+
176
+ -- Load the string into a chunk; fail on error
177
+ chunk, err = loadstring(chunkstr)
178
+ if err ~= nil then
179
+ return nil, err
180
+ end
181
+
182
+ -- Set the chunk's environment, enable the debug hook, and execute it
183
+ setfenv(chunk, env)
184
+ co = coroutine.create(chunk)
185
+ debug.sethook(co, hook, "crl")
186
+ done, err = coroutine.resume(co)
187
+
188
+ if done == true then
189
+ err = nil
190
+ end
191
+
192
+ -- Collect and return the results
193
+ return env._OUTPUT, err
194
+ end
195
+ return _wrap
196
+ end
197
+
198
+ -- Listen on stdin for Lua chunks, parse and execute them, and print the
199
+ -- results of each on stdout.
200
+ function main(arg)
201
+ if #arg ~= 2 then
202
+ io.stderr:write(string.format("usage: %s MAXLINES MAXCALLS\n", arg[0]))
203
+ os.exit(1)
204
+ end
205
+
206
+ -- Create a wrapper function, wrap()
207
+ local wrap = make_wrapper(tonumber(arg[1]), tonumber(arg[2]))
208
+
209
+ -- Turn off buffering, and loop through the input
210
+ io.stdout:setvbuf("no")
211
+ while true do
212
+ -- Read in a chunk
213
+ local chunkstr = ""
214
+ while true do
215
+ local line = io.stdin:read("*l")
216
+ if chunkstr == "" and line == nil then
217
+ -- On EOF, exit.
218
+ os.exit(0)
219
+ elseif line == "." or line == nil then
220
+ -- Finished this chunk; move on to the next step
221
+ break
222
+ elseif chunkstr ~= "" then
223
+ chunkstr = chunkstr .. "\n" .. line
224
+ else
225
+ chunkstr = line
226
+ end
227
+ end
228
+
229
+ -- Parse and execute the chunk
230
+ local res, err
231
+ res, err = wrap(chunkstr, env, hook)
232
+
233
+ -- Write out the results
234
+ if err == nil then
235
+ io.stdout:write("'", res, "', true\n.\n")
236
+ else
237
+ io.stdout:write("'", err, "', false\n.\n")
238
+ end
239
+ end
240
+ end
241
+
242
+ -- If called as a script instead of imported as a library, run main().
243
+ if arg ~= nil then
244
+ main(arg)
245
+ end