Add General MIDI interface emulation
[jpcrr.git] / datafiles / luakernel
blobdf133e6e29f0afb012bf10b433ec8d0353456bf4
1 --
2 -- Copyright 2009-2010 Ilari Liusvaara
3 --
4 -- Licenced under GNU GPL v2.
5 --
7 -- Exported tables:
8 --      - args
9 --              Contains user-level arguments.
11 -- Exported functions:
12 --      - All lua standard functions in tables main, "coroutine", "string" and "table".
13 --      - modulus_split(number num, number...)
14 --              Returns quotents and quotent remainders of number divided by given dividers.
15 --              The number of results returned is equal to number of numbers passed. The
16 --              dividers must be in decreasing order and all dividers must be nonzero and
17 --              should be >1.
18 --      - assert(object ret, object err)
19 --              If ret is considered true, return ret. Otherwise raise err as error. Exception
20 --              if err is nil too, then ret is returned anyway.
21 --      - bit.none(number...)
22 --              Returns 48-bit number that has those bits set that are set in none of its
23 --              arguments.
24 --      - bit.any(number...)
25 --              Returns 48-bit number that has those bits set that are set in any of its
26 --              arguments.
27 --      - bit.parity(number...)
28 --              Returns 48-bit number that has those bits set that are set in even number
29 --              of its arguments.
30 --      - bit.any(number...)
31 --              Returns 48-bit number that has those bits set that are set in all of its
32 --              arguments.
33 --      - bit.lshift(number num, number shift)
34 --              Returns 48 rightmost bits of num shifted by shift places left. Going outside
35 --              shift range 0-47 produces unpredicatable results.
36 --      - bit.rshift(number num, number shift)
37 --              Returns 48 rightmost bits of num shifted by shift places right. Going outside
38 --              shift range 0-47 produces unpredicatable results.
39 --      - bit.arshift(number num, number shift)
40 --              Returns 48 rightmost bits of num shifted by shift places right and bit 47
41 --              value copied to all incoming bits. Going outside shift range 0-47 produces
42 --              unpredicatable results.
43 --      - bit.add(number...)
44 --              Returns sum of all passed numbers modulo 2^48.
45 --      - bit.addneg(number...)
46 --              Returns 0 minus sum of all passed numbers modulo 2^48.
47 --      - bit.addalt(number...)
48 --              Returns sum of odd arguments (first is odd) minus sum of even arguments modulo
49 --               2^48.
50 --      - bit.rol(number num, number shift)
51 --              Returns 48 rightmost bits of num rotated by shift places left. Going outside
52 --              shift range 0-47 produces unpredicatable results.
53 --      - bit.ror(number num, number shift)
54 --              Returns 48 rightmost bits of num rotated by shift places right. Going outside
55 --              shift range 0-47 produces unpredicatable results.
56 --      - bit.bswap2(number num)
57 --              Returns 16 rightmost bits of num byte-swapped.
58 --      - bit.bswap3(number num)
59 --              Returns 24 rightmost bits of num byte-swapped.
60 --      - bit.bswap4(number num)
61 --              Returns 32 rightmost bits of num byte-swapped.
62 --      - bit.bswap5(number num)
63 --              Returns 40 rightmost bits of num byte-swapped.
64 --      - bit.bswap6(number num)
65 --              Returns 48 rightmost bits of num byte-swapped.
66 --      - bit.signextend(number num, number bitnum)
67 --              Copy bitnum'th bit of num to all higher bits of num and return result. Going
68 --              outside bitnum range of 0-47 produces unpredictable results.
69 --      - bit.tosigned(number num, number bitnum)
70 --              Mask off bitnum'th bit and all higher bits. If bitnum'th bit of num was set,
71 --              perform 2s complement on number and negate the result.
72 --      - bit.tohex(number num)
73 --              Returns hexadecimal string representation of number.
74 --      - jpcrr.wait_event()
75 --              Waits for event. Returns event type and extra message (if present). Event
76 --              Types are "lock", "stop", "attach" and "message". Note that if you get event
77 --              of type "lock", you are now in frame hold.
78 --      - jpcrr.poll_event()
79 --              Same as wait_event(), but does not wait for event to occur (returns nil if there
80 --              is no event).
81 --      - jpcrr.pc_running()
82 --              Returns true if PC is running.
83 --      - jpcrr.clock_time()
84 --              Returns current time or nil if no PC.
85 --      - jpcrr.pc_connected()
86 --              Returns true if PC is connected.
87 --      - jpcrr.in_frame_hold()
88 --              Returns true if in frame hold, false otherwise.
89 --      - jpcrr.keypressed(number key)
90 --              Return true if key is pressed, else false.
91 --      - jpcrr.keypressed_edge(number key)
92 --              Return true if key is pressed at input edge, else false.
93 --      - jpcrr.release_vga()
94 --              Allow VGA to exit frame hold mode. Wait for frame hold first.
95 --      - jpcrr.vga_resolution()
96 --              Return VGA x and y resolutions. -1x-1 or 0x0 is returned if no valid resolution.
97 --              Should only be called during frame hold.
98 --      - jpcrr.frame_number()
99 --              Return current VGA frame number or nil if no PC present.
100 --      - jpcrr.shutdown_emulator()
101 --              Shutdown the entiere emulator immediately (graceful shutdown, PCRunner only).
102 --      - jpcrr.hud.left_gap(number flags, number gap)
103 --              Set left gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
104 --              1 (2) is set, dump to video dump.
105 --      - jpcrr.hud.right_gap(number flags, number gap)
106 --              Set right gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
107 --              1 (2) is set, dump to video dump.
108 --      - jpcrr.hud.top_gap(number flags, number gap)
109 --              Set top gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
110 --              1 (2) is set, dump to video dump.
111 --      - jpcrr.hud.bottom_gap(number flags, number gap)
112 --              Set bottom gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
113 --              1 (2) is set, dump to video dump.
114 --      - jpcrr.hud.white_solid_box(number flags, number x, number y, number w, number h)
115 --              Draw with solid opaque box.
116 --      - jpcrr.hud.box(number flags, number x, number y, number w, number h, number linethick,
117 --                      number lineRed, number lineGreen, number lineBlue, number lineAlpha,
118 --                      number fillRed, number fillGreen, number fillBlue, number fillAlpha)
119 --              Draw box with specified size, border line thickness, line color and fill color.
120 --      - jpcrr.hud.circle(number flags, number x, number y, number r, number linethick,
121 --                      number lineRed, number lineGreen, number lineBlue, number lineAlpha,
122 --                      number fillRed, number fillGreen, number fillBlue, number fillAlpha)
123 --              Draw circle with specified size, border line thickness, line color and fill color.
124 --      - jpcrr.hud.bitmap(number flags, number x, number y, string bmap,
125 --                      number fgRed, number fgGreen, number fgBlue, number fgAlpha,
126 --                      number bgRed, number bgGreen, number bgBlue, number bgAlpha)
127 --              Draw bitmap with specified foreground color and background color.
128 --      - jpcrr.hud.bitmap_binary(number flags, number x, number y, string bmap,
129 --                      number fgRed, number fgGreen, number fgBlue, number fgAlpha,
130 --                      number bgRed, number bgGreen, number bgBlue, number bgAlpha)
131 --              Draw binary bitmap with specified foreground color and background color.
132 --      - jpcrr.hud.changen(number flags, number x, number y, string text,
133 --                      number fgRed, number fgGreen, number fgBlue, number fgAlpha,
134 --                      number bgRed, number bgGreen, number bgBlue, number bgAlpha,
135 --                      boolean multiline)
136 --              Output string using chargen.
137 --      - jpcrr.events.count()
138 --              Return current event count. Nil if no PC.
139 --      - jpcrr.events.current_sequence()
140 --              Return sequence number of next event (event sequence numbers are 0-based). Nil if
141 --              no PC, -1 if at end of movie.
142 --      - jpcrr.events.by_sequence(number seq)
143 --              Return array for specified event. Nil if no PC, empty array if not valid sequence
144 --              number. Otherwise, first element of array is timestamp (numeric), the second is
145 --              event class and rest are the arguments.
146 --      - jpcrr.joystick_state()
147 --              Returns nil if no joystick. Otherwise returns hold times for all four axis (numeric)
148 --              followed by button states (boolean).
149 --      - jpcrr.keyboard_leds()
150 --              Returns nil if no keyboard, false if LED status is unknown. Otherwise returns three
151 --              booleans, first being state of num lock, second being state of caps lock and third
152 --              being state of scroll lock.
153 --      - jpcrr.mouse_state()
154 --              Returns nil if no mouse. Otherwise returns X, Y and Z axis pending motions (numeric)
155 --              followed by button states (5 booleans).
156 --      - jpcrr.component_encode(table components)
157 --              Return component encoding for specified components.
158 --      - jpcrr.component_decode(string line)
159 --              Return component decoding for specified line, nil/nil if it doesn't encode
160 --              anything, nil/string if parse error occurs (the error is the second return).
161 --      - jpcrr.save_state(string name)
162 --              Savestate into specified file. Returns name used.
163 --      - jpcrr.save_movie(string name)
164 --              Save movie into specified file. Returns name used.
165 --      - jpcrr.load_state_normal(string name)
166 --              Load specified savestate. Returns name used.
167 --      - jpcrr.load_state_preserve_events(string name)
168 --              Load specified savestate, preserving events. Returns name used.
169 --      - jpcrr.load_state_movie(string name)
170 --              Load specified savestate as movie. Returns name used.
171 --      - jpcrr.assemble()
172 --              Open system settings dialog.
173 --      - jpcrr.change_authors()
174 --              Open change authors dialog.
175 --      - jpcrr.exit = function()
176 --              Exit the Lua VM.
177 --      - jpcrr.ram_dump(string name, boolean binary)
178 --              Dump PC memory to specified file. If binary is true, dump is binary, otherwise
179 --              textual hexadecimal dump.
180 --      - jpcrr.write_byte(number addr, number value)
181 --              Write byte to specified physical address.
182 --      - jpcrr.write_word(number addr, number value)
183 --              Write word to specified physical address (little endian).
184 --      - jpcrr.write_dword(number addr, number value)
185 --              Write dword to specified physical address (little endian).
186 --      - jpcrr.read_byte(number addr)
187 --              Return byte from specified physical address.
188 --      - jpcrr.read_word(number addr)
189 --              Return word from specified physical address (little endian).
190 --      - jpcrr.read_dword(number addr)
191 --              Return dword from specified physical address (little endian).
192 --      - jpcrr.read_byte_signed(number addr)
193 --              Return signed byte from specified physical address.
194 --      - jpcrr.read_word_signed(number addr)
195 --              Return signed word from specified physical address (little endian).
196 --      - jpcrr.read_dword_signed(number addr)
197 --              Return signed dword from specified physical address (little endian).
198 --      - jpcrr.timed_trap(number nsecs)
199 --              Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
200 --      - jpcrr.vretrace_start_trap(boolean is_on)
201 --              Set trap on vretrace start on/off.
202 --      - jpcrr.vretrace_end_trap(boolean is_on)
203 --              Set trap on vretrace end on/off.
204 --      - jpcrr.bios_kbd_trap(boolean is_on)
205 --              Set trap on BIOS kbd on/off.
206 --      - jpcrr.pc_start()
207 --              Start PC execution.
208 --      - jpcrr.pc_stop()
209 --              Stop PC execution.
210 --      - jpcrr.set_pccontrol_pos(number x, number y)
211 --              Set position of PCControl window.
212 --      - jpcrr.set_luaplugin_pos(number x, number y)
213 --              Set position of LuaPlugin window.
214 --      - jpcrr.set_pcmonitor_pos(number x, number y)
215 --              Set position of PCMonitor window.
216 --      - jpcrr.set_pcstartstoptest_pos(number x, number y)
217 --              Set position of PCStartStopTest window.
218 --      - jpcrr.set_virtualkeyboard_pos(number x, number y)
219 --              Set position of VirtualKeyboard window.
220 --      - jpcrr.stringlessthan(String x, String y)
221 --              Return true if x is before y in codepoint lexical order, otherwise false.
222 --      - jpcrr.screenshot(boolean include_hud)
223 --              Take screen shot (Requires monitor). If include_hud is true, include HUD
224 --              (as shown on screen). Note that this should only be called during frame
225 --              hold or results are pretty much undefined.
226 --      - jpcrr.sendevent(string class, string/number...)
227 --              Sends specified event.
228 --      - jpcrr.sendevent_lowbound(number lowbound, string class, string/number...)
229 --              Sends specified event with specified time low bound.
230 --      - jpcrr.movie_rerecords()
231 --              Return number of rerecords (nil if no movie loaded).
232 --      - jpcrr.movie_length()
233 --              Return length of movie in ns (nil if no movie loaded).
234 --      - jpcrr.movie_headers()
235 --              Return headers of movie as array of arrays (nil if no movie loaded).
236 --      - jpcrr.register_redraw_function(function)
237 --              This function is called every time screen is redrawn. It is called with
238 --              VGA lock held and that lock is automatically released after call. If this
239 --              function has been registered, no lock events will be generated.
240 --      - jpcrr.register_message_function(function)
241 --              This function is called with message as parameter every time message is
242 --              received. Suppresses message events.
243 --      - jpcrr.register_attach_function(function)
244 --              This function is called every time attach is
245 --              received. Suppresses attach events.
246 --      - jpcrr.register_stop_function(function)
247 --              This function is called every time stop is
248 --              received. Suppresses stop events.
249 --      - jpcrr.register_uiaction_function(function)
250 --              This function is called with widget name as parameter every time
251 --              UI action event is received. Suppresses ui action events.
252 --      - jpcrr.stop_and_execute(function)
253 --              Stop PC execution and call specified function after PC has stopped
254 --              fully. Note that only handler functions receive events until this
255 --              returns.
257 --      I/O functions have the following conventions. If function returns any real data, the first
258 --      return value returns this data or is nil. Otherwise first return value is true or false.
259 --      If first return value is nil or false, then the second return value gives textual error
260 --      message for failed operation, or is nil if EOF occured before anything was read.
262 --      Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
263 --      success or failure.
265 --      Specifying nil as name of file results random filename being used (it even works with unlink,
266 --      mkdir, rename and read-only access, but doesn't make any sense there).
268 --      Specifying empty filename prompts for file (doesn't work with mkdir, rename nor unlink). Use
269 --      '/<title>' to specify title for prompt dialog.
271 --      Class: BinaryFile:
272 --              Binary file for RO or RW access. Methods are as follows:
273 --              - name()
274 --                      Return name of file.
275 --              - length()
276 --                      Return length of file.
277 --              - set_length(number length)
278 --                      Truncate file to specified length
279 --              - read(number offset, number length)
280 --                      Read up to length bytes from offset.
281 --              - write(number offset, string content)
282 --                      Write content to specified offset.
283 --              - close()
284 --                      Close the file.
285 --      Class: BinaryInput:
286 --              Binary file for sequential input. Methods are as follows:
287 --              - name()
288 --                      Return name of file.
289 --              - four_to_five()
290 --                      Return BinaryInput that is four to five decoding of this stream.
291 --              - text()
292 --                      Return stream as TextInput.
293 --              - inflate()
294 --                      Return BinaryInput that is inflate of this stream.
295 --              - read(number bytes)
296 --                      Read up to bytes bytes from file.
297 --              - read()
298 --                      Read the entiere file at once.
299 --              - close()
300 --                      Close the file.
301 --              Character set for binary files is Latin-1.
303 --      Class: BinaryOutput:
304 --              Binary file for sequential output. Methods are as follows:
305 --              - name()
306 --                      Return name of file.
307 --              - four_to_five()
308 --                      Return BinaryOutput that writes four to five encoded output to this stream.
309 --              - text()
310 --                      Return stream as TextOutput.
311 --              - deflate()
312 --                      Return BinaryOutput that writes deflate output to this stream.
313 --              - write(string content)
314 --                      Write string to file.
315 --              - close()
316 --                      Close the file.
317 --              Character set for binary files is Latin-1.
319 --      Class: TextInput:
320 --              - name()
321 --                      Return name of file.
322 --              - read()
323 --                      Read line from file.
324 --              - read_component()
325 --                      Read next componented line into array.
326 --              - lines()
327 --                      Line iterator function.
328 --              - close()
329 --                      Close the file.
330 --      Character set for text files is UTF-8.
332 --      Class: TextOutput:
333 --              - name()
334 --                      Return name of file.
335 --              - write(string line)
336 --                      Write line line to file.
337 --              - write_component(table components)
338 --                      Write componented line.
339 --              - close()
340 --                      Close the file.
341 --              Character set for text files is UTF-8.
343 --      Class ArchiveIn:
344 --              - member(string name)
345 --                      Open substream for member name. The methods are the same as for io.opentextin.
346 --              - member_binary(string name)
347 --                      Open binary (four to five) substream for member name. The methods are the same as
348 --                      for io.openbinaryin.
349 --              - close()
350 --                      Close the file. Any opened substreams are invalidated.
351 --              - member_list()
352 --                      Return table listing all members of archive (sorted by name).
353 --      Class ArchiveOut:
354 --              - member(string name)
355 --                      Open substream for member name. The methods are the same as for io.opentextout. Note that
356 --                      previous member must be closed before next can open.
357 --              - member_binary(string name)
358 --                      Open binary (four to five) substream for member name. The methods are the same as
359 --                      for io.openbinaryout. Note that previous substream must be closed before next can open.
360 --              - commit()
361 --                      Commit the file. No substream may be open. Closes the file.
362 --              - rollback()
363 --                      Rollback the file. No substream may be open. Closes the file.
365 --      - io.open(string name, string mode) -> BinaryFile
366 --              Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
367 --              write).
368 --      - io.open_read(string name) -> BinaryInput
369 --              Open file named @name as binary input stream.
370 --      - io.open_write(string name) -> BinaryOutput
371 --              Open file named @name as binary input stream.
372 --      - io.open_arch_read(string name) -> ArchiveIn
373 --              Open file named @name as input archive.
374 --      - io.open_arch_write(string name) -> ArchiveOut
375 --              Open file named @name as output archive.
376 --      - io.mkdir(string name)
377 --              Create directory name. Returns name created on success, nil on failure.
378 --      - io.unlink(string name)
379 --              Delete file/directory name. Returns name deleted on success, nil on failure.
380 --      - io.rename(string old, string new)
381 --              Rename file old -> new. Returns old, new on success, nil on failure.
382 --      - io.transform.text()
383 --              Returns function that calls text() method of its parameter.
384 --      - io.transform.four_to_five()
385 --              Returns function that calls four_to_five() method of its parameter.
386 --      - io.transform.deflate()
387 --              Returns function that calls deflate() method of its parameter.
388 --      - io.transform.inflate()
389 --              Returns function that calls inflate() method of its parameter.
390 --      - io.dotransform(object obj, function...)
391 --              Call specified functions on specified object. If any function fails (first argument nil
392 --              or false), call close method on preceeding object. Otherwise call specified functions
393 --              chained left to right and return the result.
394 --      - io.dotransform2(object obj, string err, function...)
395 --              Similar to dotransform except if obj is nil or false, returns obj, err.
398 local stopping = false;
399 local mesage_function = nil;
400 local lock_function = nil;
401 local uiaction_function = nil;
402 local stop_function = nil;
403 local attach_function = nil;
405 local handle, err, chunk, indication, k, v;
407 local loadmod = loadmodule;
408 loadmodule = nil;
410 local export_module_in = function(tab, modname, prefix)
411         local fun = loadmod(modname);
412         for k, v in pairs(fun) do
413                 tab[(prefix or "") .. k] = v;
414         end
417 jpcrr = {};
418 jpcrr.hud = {};
419 jpcrr.events = {};
420 jpcrr.window = {};
421 jpcrr.memorysearch = {};
422 bit = {};
423 io = {};
424 local HUD = {};
426 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
427 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
428 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
429 export_module_in(jpcrr.events, "org.jpc.luaextensions.Events");
430 export_module_in(jpcrr.window, "org.jpc.luaextensions.Window");
431 export_module_in(bit, "org.jpc.luaextensions.Bitops");
432 export_module_in(jpcrr.memorysearch, "org.jpc.luaextensions.MemorySearch");
433 export_module_in(HUD, "org.jpc.luaextensions.HUD");
435 -- HUD bindings.
436 local HUD = HUD.HUD;
437 jpcrr.HUD = HUD;
439 -- Few misc functions.
440 assert = function(val, err)
441         if (not val) and err then
442                 error(err);
443         end
444         return val;
447 modulus_split = function(number, ...)
448         local dividers = {...};
449         local results = {};
450         local rem;
452         for k, v in ipairs(dividers) do
453                 rem = number % v;
454                 table.insert(results, (number - rem) / v);
455                 number = rem;
456         end
458         table.insert(results, number);
459         return unpack(results);
462 jpcrr.register_redraw_function = function(f)
463         if f and type(f) ~= "function" then
464                 error("Incorrect type of argument to register_redraw_function");
465         end
466         lock_function = f;
469 jpcrr.register_message_function = function(f)
470         if f and type(f) ~= "function" then
471                 error("Incorrect type of argument to register_message_function");
472         end
473         message_function = f;
476 jpcrr.register_stop_function = function(f)
477         if f and type(f) ~= "function" then
478                 error("Incorrect type of argument to register_stop_function");
479         end
480         stop_function = f;
483 jpcrr.register_attach_function = function(f)
484         if f and type(f) ~= "function" then
485                 error("Incorrect type of argument to register_attach_function");
486         end
487         attach_function = f;
490 jpcrr.register_uiaction_function = function(f)
491         if f and type(f) ~= "function" then
492                 error("Incorrect type of argument to register_uiaction_function");
493         end
494         uiaction_function = f;
499 local getmtable = getmetatable;
500 local toString = tostring;
501 local inject_binary_file;
502 local inject_binary_input;
503 local inject_binary_output;
504 local inject_text_input;
505 local inject_text_output;
506 local inject_archive_input;
507 local inject_archive_output;
509 -- Class member injectors.
510 inject_binary_file = function(obj, name)
511         local _name = name;
512         getmtable(obj).name = function(obj)
513                 return _name;
514         end
515         getmtable(obj).__index = function(tab, name)
516                 local x = getmtable(obj)[name];
517                 if x then
518                         return x;
519                 end
520                 error("Invalid method " .. name .. " for BinaryFile");
521         end
522         return obj;
525 inject_binary_input = function(obj, underlying, name)
526         local _name = name;
527         local old_four_to_five = getmtable(obj).four_to_five;
528         local old_inflate = getmtable(obj).inflate;
529         local old_text = getmtable(obj).text;
530         local old_read = getmtable(obj).read;
531         local old_close = getmtable(obj).close;
532         local underlying_object = underlying;
534         getmtable(obj).name = function(obj)
535                 return _name;
536         end
537         getmtable(obj).four_to_five = function(obj)
538                 local res, err;
539                 res, err = old_four_to_five(obj);
540                 if not res then
541                         return res, err;
542                 end
543                 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
544         end
545         getmtable(obj).inflate = function(obj)
546                 local res, err;
547                 res, err = old_inflate(obj);
548                 if not res then
549                         return res, err;
550                 end
551                 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
552         end
553         getmtable(obj).text = function(obj)
554                 local res, err;
555                 res, err = old_text(obj);
556                 if not res then
557                         return res, err;
558                 end
559                 return inject_text_input(res, obj, "text<" .. _name .. ">");
560         end
561         getmtable(obj).read = function(obj, toread)
562                 if toread then
563                         return old_read(obj, toread);
564                 else
565                         local res = "";
566                         local ret, err;
567                         while true do
568                                 ret, err = old_read(obj, 16384);
569                                 if not ret then
570                                         if not err then
571                                                 return res;
572                                         end
573                                         return nil, err;
574                                 end
575                                 res = res .. ret;
576                         end
577                 end
578         end
579         getmtable(obj).close = function(obj)
580                 local ret, err, ret2, err2;
581                 ret, err = old_close(obj);
582                 if underlying_object then ret2, err2 = underlying_object:close(); end
583                 if ret and not ret2 then
584                         err = err2;
585                         ret = ret2;
586                 end
587                 return ret, err;
588         end
589         getmtable(obj).__index = function(tab, name)
590                 local x = getmtable(obj)[name];
591                 if x then
592                         return x;
593                 end
594                 error("Invalid method " .. name .. " for BinaryInput");
595         end
596         return obj;
599 inject_binary_output = function(obj, underlying, name)
600         local _name = name;
601         local old_four_to_five = getmtable(obj).four_to_five;
602         local old_deflate = getmtable(obj).deflate;
603         local old_text = getmtable(obj).text;
604         local old_close = getmtable(obj).close;
605         local underlying_object = underlying;
607         getmtable(obj).name = function(obj)
608                 return _name;
609         end
610         getmtable(obj).four_to_five = function(obj)
611                 local res, err;
612                 res, err = old_four_to_five(obj);
613                 if not res then
614                         return res, err;
615                 end
616                 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
617         end
618         getmtable(obj).deflate = function(obj)
619                 local res, err;
620                 res, err = old_deflate(obj);
621                 if not res then
622                         return res, err;
623                 end
624                 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
625         end
626         getmtable(obj).text = function(obj)
627                 local res, err;
628                 res, err = old_text(obj);
629                 if not res then
630                         return res, err;
631                 end
632                 return inject_text_output(res, obj, "text<" .. _name .. ">");
633         end
634         getmtable(obj).close = function(obj)
635                 local ret, err, ret2, err2;
636                 ret, err = old_close(obj);
637                 if underlying_object then ret2, err2 = underlying_object:close(); end
638                 if ret and not ret2 then
639                         err = err2;
640                         ret = ret2;
641                 end
642                 return ret, err;
643         end
644         getmtable(obj).__index = function(tab, name)
645                 local x = getmtable(obj)[name];
646                 if x then
647                         return x;
648                 end
649                 error("Invalid method " .. name .. " for BinaryOutput");
650         end
651         return obj;
654 inject_text_input = function(obj, underlying, name)
655         local _name = name;
656         local old_close = getmtable(obj).close;
657         local underlying_object = underlying;
659         getmtable(obj).lines = function(obj)
660                 return function(state, prevline)
661                         return state:read();
662                 end, obj, nil;
663         end
664         getmtable(obj).name = function(obj)
665                 return _name;
666         end
667         getmtable(obj).close = function(obj)
668                 local ret, err, ret2, err2;
669                 ret, err = old_close(obj);
670                 if underlying_object then ret2, err2 = underlying_object:close(); end
671                 if ret and not ret2 then
672                         err = err2;
673                         ret = ret2;
674                 end
675                 return ret, err;
676         end
677         getmtable(obj).__index = function(tab, name)
678                 local x = getmtable(obj)[name];
679                 if x then
680                         return x;
681                 end
682                 error("Invalid method " .. name .. " for TextInput");
683         end
684         return obj;
687 inject_text_output = function(obj, underlying, name)
688         local _name = name;
689         local old_close = getmtable(obj).close;
690         local underlying_object = underlying;
692         getmtable(obj).name = function(obj)
693                 return _name;
694         end
695         getmtable(obj).close = function(obj)
696                 local ret, err, ret2, err2;
697                 ret, err = old_close(obj);
698                 if underlying_object then ret2, err2 = underlying_object:close(); end
699                 if ret and underlying_object then
700                         err = err2;
701                         ret = ret2;
702                 end
703                 return ret, err;
704         end
705         getmtable(obj).__index = function(tab, name)
706                 local x = getmtable(obj)[name];
707                 if x then
708                         return x;
709                 end
710                 error("Invalid method " .. name .. " for TextOutput");
711         end
712         return obj;
715 inject_archive_input = function(obj, name)
716         local _name = name;
717         local old_member = getmtable(obj).member;
718         local old_member_list = getmtable(obj).member_list;
719         getmtable(obj).member = function(obj, member)
720                 local res, err;
721                 res, err = old_member(obj, member);
722                 if not res then
723                         return res, err;
724                 end
725                 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
726         end
727         getmtable(obj).name = function(obj)
728                 return _name;
729         end
730         getmtable(obj).member_list = function(obj)
731                 local tab = old_member_list(obj);
732                 if tab then table.sort(tab, jpcrr.stringlessthan); end
733                 return tab;
734         end
735         getmtable(obj).__index = function(tab, name)
736                 local x = getmtable(obj)[name];
737                 if x then
738                         return x;
739                 end
740                 error("Invalid method " .. name .. " for ArchiveInput");
741         end
742         return obj;
745 inject_archive_output = function(obj, name)
746         local _name = name;
747         local old_member = getmtable(obj).member;
748         getmtable(obj).member = function(obj, member)
749                 local res, err;
750                 res, err = old_member(obj, member);
751                 if not res then
752                         return res, err;
753                 end
754                 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
755         end
756         getmtable(obj).name = function(obj)
757                 return _name;
758         end
759         getmtable(obj).__index = function(tab, name)
760                 local x = getmtable(obj)[name];
761                 if x then
762                         return x;
763                 end
764                 error("Invalid method " .. name .. " for ArchiveOutput");
765         end
766         return obj;
770 -- Redefined routines.
772         local rprint = print_console_msg;
773         print_console_msg = nil;
774         print = function(...)
775                 local x = "";
776                 local y = {...};
777                 local i;
778                 for i = 1,#y do
779                         if i > 1 then
780                                 x = x .. "\t" .. toString(y[i]);
781                         else
782                                 x = toString(y[i]);
783                         end
784                 end
785                 rprint(x);
786         end
787         print_console_msg = nil;
792 -- I/O routines.
793 local stringfind = string.find;
794 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
795 local selectname = loadmod("org.jpc.luaextensions.BaseFSOps").opensave_dialog;
796 local path = args["luapath"] or ".";
797 local toresourcename = function(resname, save, text)
798         if not resname then
799                 return randname(path .. "/", "luatemp-");
800         end
802         if resname == "" and text then
803                 local a, b;
804                 a, b = selectname(save, text);
805                 return a, (a or b);
806         end
808         if stringfind(resname, "^/") then
809                 if not text then
810                         error("Bad resource name (case 2): " .. resname);
811                 end
812                 local a, b;
813                 a, b = selectname(save, string.sub(resname, 2));
814                 return a, (a or b);
815         end
817         if not stringfind(resname, "[%d%l%u_%-]") then
818                 error("Bad resource name (case 1): " .. resname);
819         end
820         if stringfind(resname, "%.%.") then
821                 error("Bad resource name (case 3): " .. resname);
822         end
823         if stringfind(resname, "\\") then
824                 error("Bad resource name (case 4): " .. resname);
825         end
827         return resname, path .. "/" .. resname;
832         local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
833         local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
834         local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
835         local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
836         local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
838         local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
839         local mkdir = baseFS.mkdir;
840         local unlink = baseFS.unlink;
841         local rename = baseFS.rename;
843         local getmtable = getmetatable;
845         loadfile = function(_script)
846                 local file, file2, err, content;
847                 local x, y;
848                 x, y = toresourcename(_script, false, "Select script to load");
849                 if not x then return x, y; end
850                 file, err = openbinin(y, "r");
851                 if not file then
852                         return nil, "Can't open " .. _script .. ": " .. err;
853                 end
854                 file2, err = file:text();
855                 if not file2 then
856                         return nil, "Can't transform " .. _script .. ": " .. err;
857                 end
858                 content = "";
859                 line = file2:read();
860                 while line do
861                         content = content .. line .. "\n";
862                         line = file2:read();
863                 end
864                 file2:close();
865                 file:close();
866                 return loadstring(content, _script);
867         end
869         io.open = function(name, mode)
870                 local _name;
871                 local res, err;
872                 local y;
873                 if mode == "r" then
874                         _name, y = toresourcename(name, false, "Select file to read");
875                 else
876                         _name, y = toresourcename(name, true, "Select file to write");
877                 end
878                 if not _name then return _name, y; end
879                 res, err = openbinary(y, mode);
880                 if not res then
881                         return res, err;
882                 end
883                 return inject_binary_file(res, _name);
884         end
886         io.open_arch_read = function(name)
887                 local _name = name;
888                 local res, err;
889                 local y;
890                 _name, y = toresourcename(name, false, "Select archive to read");
891                 if not _name then return _name, y; end
892                 res, err = openarchin(y);
893                 if not res then
894                         return res, err;
895                 end
896                 return inject_archive_input(res, _name);
897         end
899         io.open_arch_write = function(name)
900                 local _name = name;
901                 local res, err;
902                 local y;
903                 _name, y = toresourcename(name, true, "Select archive to write");
904                 if not _name then return _name, y; end
905                 res, err = openarchout(y);
906                 if not res then
907                         return res, err;
908                 end
909                 return inject_archive_output(res, _name);
910         end
912         io.open_read = function(name)
913                 local _name = name;
914                 local res, err;
915                 local y;
916                 _name, y = toresourcename(name, false, "Select file to read");
917                 if not _name then return _name, y; end
918                 res, err = openbinin(y);
919                 if not res then
920                         return res, err;
921                 end
922                 return inject_binary_input(res, nil, _name);
923         end
925         io.open_write = function(name)
926                 local _name = name;
927                 local res, err;
928                 local y;
929                 _name, y = toresourcename(name, true, "Select file to write");
930                 if not _name then return _name, y; end
931                 res, err = openbinout(y);
932                 if not res then
933                         return res, err;
934                 end
935                 return inject_binary_output(res, nil, _name);
936         end
938         io.mkdir = function(name)
939                 local _name, y;
940                 _name, y = toresourcename(name);
941                 if mkdir(y) then
942                         return _name;
943                 else
944                         return nil;
945                 end
946         end
948         io.unlink = function(name)
949                 local _name, y;
950                 _name, y = toresourcename(name);
951                 if unlink(y) then
952                         return _name;
953                 else
954                         return nil;
955                 end
956         end
958         io.rename = function(name1, name2)
959                 local _name, y;
960                 local _name2, y2;
961                 _name, y = toresourcename(name1);
962                 _name2, y2 = toresourcename(name2);
963                 if rename(y, y2) then
964                         return _name, _name2;
965                 else
966                         return nil;
967                 end
968         end
970         io.transform = {};
972         io.transform.text = function()
973                 return function(obj)
974                         return obj:text();
975                 end
976         end
978         io.transform.four_to_five = function()
979                 return function(obj)
980                         return obj:four_to_five();
981                 end
982         end
984         io.transform.inflate = function()
985                 return function(obj)
986                         return obj:inflate();
987                 end
988         end
990         io.transform.deflate = function()
991                 return function(obj)
992                         return obj:deflate();
993                 end
994         end
996         io.dotransform = function(obj, ...)
997                 local todo = {...};
998                 local k, v;
999                 local obj2, err;
1000                 for k, v in ipairs(todo) do
1001                         obj2, err = v(obj);
1002                         if not obj2 then
1003                                 obj:close();
1004                                 return nil, err;
1005                         end
1006                         obj = obj2;
1007                 end
1008                 return obj;
1009         end
1011         io.dotransform2 = function(obj, err, ...)
1012                 if not obj then
1013                         return obj, err;
1014                 end
1015                 return io.dotransform(obj, err, ...);
1016         end
1020 -- Various stuff built on top of ECI.
1021 local invoke = jpcrr.invoke;
1022 local invokecall = jpcrr.call;
1023 local invokesync = jpcrr.invoke_synchronous;
1025 jpcrr.sendevent = function(...)
1026         local arguments = {...};
1027         local k, v;
1028         for k, v in ipairs(arguments) do
1029                 arguments[k] = toString(v);
1030         end
1031         invokesync("sendevent", arguments);
1034 jpcrr.sendevent_lowbound = function(...)
1035         local arguments = {...};
1036         local k, v;
1037         for k, v in ipairs(arguments) do
1038                 arguments[k] = toString(v);
1039         end
1040         invokesync("sendevent-lowbound", arguments);
1043 jpcrr.save_state = function(name)
1044         local _name, _fname;
1045         _name, _fname = toresourcename(name, true, "File to savestate to");
1046         invokesync("state-save", {_fname});
1047         return _name;
1050 jpcrr.save_movie = function(name)
1051         local _name, _fname;
1052         _name, _fname = toresourcename(name, true, "File to save movie to");
1053         invokesync("movie-save", {_fname});
1054         return _name;
1057 jpcrr.load_state_normal = function(name)
1058         local _name, _fname;
1059         _name, _fname = toresourcename(name, false, "File to loadstate from");
1060         invokesync("state-load", {_fname});
1061         return _name;
1064 jpcrr.load_state_preserve_events = function(name)
1065         local _name, _fname;
1066         _name, _fname = toresourcename(name, false, "File to loadstate (preserve events) from");
1067         invokesync("state-load-noevents", {_fname});
1068         return _name;
1071 jpcrr.load_state_movie = function(name)
1072         local _name, _fname;
1073         _name, _fname = toresourcename(name, false, "File to load movie from");
1074         invokesync("movie-load", {_fname});
1075         return _name;
1078 jpcrr.assemble = function()
1079         invokesync("pc-assemble");
1082 jpcrr.change_authors = function()
1083         invokesync("change-authors");
1086 jpcrr.ram_dump = function(name, binary)
1087         local _name, _fname;
1088         _name, _fname = toresourcename(name, true, "Select file to ramdump to");
1089         if binary then
1090                 invokesync("ram-dump-binary", {_fname});
1091         else
1092                 invokesync("ram-dump-text", {_fname});
1093         end
1094         return _name;
1097 local poll_event = jpcrr.poll_event;
1098 local _print = print;
1099 local _unlock = jpcrr.release_vga;
1100 jpcrr.poll_event = function()
1101         local a, b;
1102         local failed = false;
1103         while not failed do
1104                 a, b = poll_event();
1105                 if not a then
1106                         failed = true;
1107                 end
1108                 if a and a == "message" and message_function then
1109                         a, b = pcall(message_function, b);
1110                         if not a then
1111                                 _print("Error running message callback: " .. b);
1112                         end
1113                         a = nil;
1114                 end
1115                 if a and a == "uiaction" and uiaction_function then
1116                         a, b = pcall(uiaction_function, b);
1117                         if not a then
1118                                 _print("Error running uiaction callback: " .. b);
1119                         end
1120                         a = nil;
1121                 end
1122                 if a and a == "stop" and stop_function then
1123                         a, b = pcall(stop_function);
1124                         if not a then
1125                                 _print("Error running stop callback: " .. b);
1126                         end
1127                         a = nil;
1128                 end
1129                 if a and a == "attach" and attach_function then
1130                         a, b = pcall(attach_function);
1131                         if not a then
1132                                 _print("Error running attach callback: " .. b);
1133                         end
1134                         a = nil;
1135                 end
1136                 if a and a == "lock" and lock_function then
1137                         a, b = pcall(lock_function);
1138                         _unlock();
1139                         if not a then
1140                                 _print("Error running redraw callback: " .. b);
1141                         end
1142                         if stoppping then
1143                                 return "lock";
1144                         end
1145                         a = nil;
1146                 end
1147                 if a and a == "lock" and stopping then
1148                         _unlock();
1149                         return "lock";
1150                 end
1151         end
1152         return a, b;
1156 local wait_event = jpcrr.wait_event;
1157 local _print = print;
1158 local _unlock = jpcrr.release_vga;
1159 jpcrr.wait_event = function()
1160         local a, b;
1161         while not a do
1162                 a, b = wait_event();
1163                 if a and a == "message" and message_function then
1164                         a, b = pcall(message_function, b);
1165                         if not a then
1166                                 _print("Error running message callback: " .. b);
1167                         end
1168                         a = nil;
1169                 end
1170                 if a and a == "uiaction" and uiaction_function then
1171                         a, b = pcall(uiaction_function, b);
1172                         if not a then
1173                                 _print("Error running uiaction callback: " .. b);
1174                         end
1175                         a = nil;
1176                 end
1177                 if a and a == "stop" and stop_function then
1178                         a, b = pcall(stop_function);
1179                         if not a then
1180                                 _print("Error running stop callback: " .. b);
1181                         end
1182                         a = nil;
1183                 end
1184                 if a and a == "attach" and attach_function then
1185                         a, b = pcall(attach_function);
1186                         if not a then
1187                                 _print("Error running attach callback: " .. b);
1188                         end
1189                         a = nil;
1190                 end
1191                 if a and a == "lock" and lock_function then
1192                         a, b = pcall(lock_function);
1193                         _unlock();
1194                         if not a then
1195                                 _print("Error running redraw callback: " .. b);
1196                         end
1197                         if stopping then
1198                                 return a, b;
1199                         end
1200                         a = nil;
1201                 end
1202         end
1203         return a, b;
1207 jpcrr.hud.left_gap = function(f, g)
1208         HUD("left_gap", f, g);
1211 jpcrr.hud.right_gap = function(f, g)
1212         HUD("right_gap", f, g);
1215 jpcrr.hud.top_gap = function(f, g)
1216         HUD("top_gap", f, g);
1219 jpcrr.hud.bottom_gap = function(f, g)
1220         HUD("bottom_gap", f, g);
1223 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
1224         HUD("hud_white_solid_box", f, x, y, w, h);
1227 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
1228         la = la or 255;
1229         fr = fr or 0;
1230         fg = fg or 0;
1231         fb = fb or 0;
1232         fa = fa or 0;
1233         HUD("box", f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa);
1236 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1237         la = la or 255;
1238         fr = fr or 0;
1239         fg = fg or 0;
1240         fb = fb or 0;
1241         fa = fa or 0;
1242         HUD("circle", f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1245 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1246         la = la or 255;
1247         fr = fr or 0;
1248         fg = fg or 0;
1249         fb = fb or 0;
1250         fa = fa or 0;
1251         HUD("bitmap", f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1254 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1255         la = la or 255;
1256         fr = fr or 0;
1257         fg = fg or 0;
1258         fb = fb or 0;
1259         fa = fa or 0;
1260         HUD("bitmap_binary", f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1263 jpcrr.hud.chargen = function(f, x, y, text, multiline, lr, lg, lb, la, fr, fg, fb, fa)
1264         la = la or 255;
1265         fr = fr or 0;
1266         fg = fg or 0;
1267         fb = fb or 0;
1268         fa = fa or 0;
1269         HUD("vga_chargen", f, x, y, text, lr, lg, lb, la, fr, fg, fb, fa, multiline)
1272 jpcrr.shutdown_emulator = function()
1273         invokesync("shutdown-emulator", {});
1276 jpcrr.set_pccontrol_pos = function(x, y)
1277         invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
1280 jpcrr.set_luaplugin_pos = function(x, y)
1281         invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
1284 jpcrr.set_pcmonitor_pos = function(x, y)
1285         invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
1288 jpcrr.set_pcstartstoptest_pos = function(x, y)
1289         invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
1292 jpcrr.set_virtualkeyboard_pos = function(x, y)
1293         invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
1296 jpcrr.exit = function()
1297         invokesync("luaplugin-terminate");
1300 jpcrr.pc_start = function()
1301         invoke("pc-start");
1304 jpcrr.pc_stop = function()
1305         invokesync("pc-stop");
1308 jpcrr.screenshot = function(include_hud)
1309         if include_hud then
1310                 invoke("screenshot-renderbuffer");
1311         else
1312                 invoke("screenshot-vgabuffer");
1313         end
1316 jpcrr.bios_kbd_trap = function(is_on)
1317         if is_on then
1318                 invokesync("trap-bios-kbd-on");
1319         else
1320                 invokesync("trap-bios-kbd-off");
1321         end
1324 jpcrr.vretrace_start_trap = function(is_on)
1325         if is_on then
1326                 invokesync("trap-vretrace-start-on");
1327         else
1328                 invokesync("trap-vretrace-start-off");
1329         end
1332 jpcrr.vretrace_end_trap = function(is_on)
1333         if is_on then
1334                 invokesync("trap-vretrace-end-on");
1335         else
1336                 invokesync("trap-vretrace-end-off");
1337         end
1340 jpcrr.timed_trap = function(nsecs)
1341         if nsecs then
1342                 invokesync("trap-timed", {toString(nsecs)});
1343         else
1344                 invokesync("trap-timed-disable");
1345         end
1348 jpcrr.write_byte = function(addr, value)
1349         invokesync("memory-write", {toString(addr), toString(value), "1"});
1352 jpcrr.write_word = function(addr, value)
1353         invokesync("memory-write", {toString(addr), toString(value), "2"});
1356 jpcrr.write_dword = function(addr, value)
1357         invokesync("memory-write", {toString(addr), toString(value), "4"});
1360 jpcrr.read_byte = function(addr)
1361         local t = {toString(addr), "1"};
1362         t = invokecall("memory-read", t);
1363         return (t or {})[1];
1366 jpcrr.read_word = function(addr)
1367         local t = {toString(addr), "2"};
1368         t = invokecall("memory-read", t);
1369         return (t or {})[1];
1372 jpcrr.read_dword = function(addr)
1373         local t = {toString(addr), "4"};
1374         t = invokecall("memory-read", t);
1375         return (t or {})[1];
1378 jpcrr.read_byte_signed = function(addr)
1379         local t = {toString(addr), "1"};
1380         t = invokecall("memory-read", t);
1381         return bit.tosigned((t or {})[1], 7);
1384 jpcrr.read_word_signed = function(addr)
1385         local t = {toString(addr), "2"};
1386         t = invokecall("memory-read", t);
1387         return bit.tosigned((t or {})[1], 15);
1390 jpcrr.read_dword_signed = function(addr)
1391         local t = {toString(addr), "4"};
1392         t = invokecall("memory-read", t);
1393         return bit.tosigned((t or {})[1], 31);
1396 local e_wait_event = jpcrr.wait_event;
1397 local running = jpcrr.pc_running;
1398 local stop_and_execute_in_progress = false;
1399 jpcrr.stop_and_execute = function(f)
1400         local a, b;
1401         _unlock();
1402         if stop_and_execute_in_progress then
1403                 return false;
1404         end
1405         if not running() then
1406                 a, b = pcall(f);
1407                 if not a then
1408                         error("Error in after stop callback: " .. b);
1409                 end
1410                 return true;
1411         end
1412         jpcrr.pc_stop();
1413         while true do
1414                 stop_and_execute_in_progress = true;
1415                 a, b = e_wait_event();
1416                 stop_and_execute_in_progress = false;
1417                 if a and a == "lock" then
1418                         _unlock();
1419                         if stopping then
1420                                 break;
1421                         end
1422                 elseif a and (a == "stop" or a == "attach") then
1423                         stopping = true;
1424                 end
1425         end
1426         stopping = false;
1427         a, b = pcall(f);
1428         if not a then
1429                 error("Error in after stop callback: " .. b);
1430         end
1431         return true;
1435 jpcrr.invoke = nil;
1436 jpcrr.invoke_synchronous = nil;
1437 jpcrr.call = null
1439 -- Dofile.
1440 dofile = function(_script)
1441         local chunk, err, indication
1442         chunk, err = loadfile(_script);
1443         if not chunk then
1444                 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1445         end
1446         return chunk();
1449 local args2 = args;
1450 args = null;
1451 args = {};
1452 for k, v in pairs(args2) do
1453         if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1454                 args[string.sub(k, 3)] = v;
1455         end
1457 jpcrr_raw = null;
1460         chunk = null;
1461         loaded, err = pcall(function()
1462                 chunk, err = loadfile(script);
1463                 if not chunk then
1464                         error(err);
1465                 end
1466         end);
1467         if not loaded then
1468                 print("Kernel: Can't load script " .. script .. ": " .. err);
1469                 invoke("luaplugin-terminate");
1470                 while true do end
1471         end
1473         script = null;
1474         indication, err = pcall(chunk);
1475         if not indication then
1476                 print("Kernel: Unprotected error in script: " .. err);
1477                 invoke("luaplugin-terminate");
1478                 while true do end
1479         end