Merge fixes in r10.9
[jpcrr.git] / luakernel.lua
blob16ebdc0a029ccf4df2ca0ac8c207915e12b51053
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_message()
75 -- Waits for message (string) to come from message queue. Reutrns nil if interrupted.
76 -- - jpcrr.poll_message()
77 -- Checks if there is message from message queue. Reutrns message if there is one,
78 -- nil if none.
79 -- - jpcrr.wait_pc_stop()
80 -- Waits for PC execution to stop (but does not attempt to actually stop it).
81 -- If script is in frame hold, the frame hold is released.
82 -- Returns true if execution got stopped, false if interrupted.
83 -- - jpcrr.pc_running()
84 -- Returns true if PC is running.
85 -- - jpcrr.clock_time()
86 -- Returns current time or nil if no PC.
87 -- - jpcrr.pc_connected()
88 -- Returns true if PC is connected.
89 -- - jpcrr.wait_pc_attach()
90 -- Wait for PC to attach.
91 -- - jpcrr.next_frame()
92 -- Wait for next frame output hold.
93 -- - jpcrr.in_frame_hold()
94 -- Returns true if in frame hold, false otherwise.
95 -- - jpcrr.keypressed(number key)
96 -- Return true if key is pressed, else false.
97 -- - jpcrr.wait_vga()
98 -- Waits for VGA to enter frame hold mode. Frame hold happens once per frame.
99 -- - jpcrr.release_vga()
100 -- Allow VGA to exit frame hold mode. Wait for frame hold first.
101 -- - jpcrr.vga_resolution()
102 -- Return VGA x and y resolutions. -1x-1 or 0x0 is returned if no valid resolution.
103 -- Should only be called during frame hold.
104 -- - jpcrr.hud.left_gap(number flags, number gap)
105 -- Set left gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
106 -- 1 (2) is set, dump to video dump.
107 -- - jpcrr.hud.right_gap(number flags, number gap)
108 -- Set right gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
109 -- 1 (2) is set, dump to video dump.
110 -- - jpcrr.hud.top_gap(number flags, number gap)
111 -- Set top gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
112 -- 1 (2) is set, dump to video dump.
113 -- - jpcrr.hud.bottom_gap(number flags, number gap)
114 -- Set bottom gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
115 -- 1 (2) is set, dump to video dump.
116 -- - jpcrr.hud.white_solid_box(number flags, number x, number y, number w, number h)
117 -- Draw with solid opaque box.
118 -- - jpcrr.hud.box(number flags, number x, number y, number w, number h, number linethick,
119 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
120 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
121 -- Draw box with specified size, border line thickness, line color and fill color.
122 -- - jpcrr.hud.circle(number flags, number x, number y, number r, number linethick,
123 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
124 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
125 -- Draw circle with specified size, border line thickness, line color and fill color.
126 -- - jpcrr.hud.bitmap(number flags, number x, number y, string bmap,
127 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
128 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
129 -- Draw bitmap with specified foreground color and background color.
130 -- - jpcrr.hud.bitmap_binary(number flags, number x, number y, string bmap,
131 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
132 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
133 -- Draw binary bitmap with specified foreground color and background color.
134 -- - jpcrr.joystick_state()
135 -- Returns nil if no joystick. Otherwise returns hold times for all four axis (numeric)
136 -- followed by button states (boolean).
137 -- - jpcrr.keyboard_leds()
138 -- Returns nil if no keyboard, false if LED status is unknown. Otherwise returns three
139 -- booleans, first being state of num lock, second being state of caps lock and third
140 -- being state of scroll lock.
141 -- - jpcrr.mouse_state()
142 -- Returns nil if no mouse. Otherwise returns X, Y and Z axis pending motions (numeric)
143 -- followed by button states (5 booleans).
144 -- - jpcrr.component_encode(table components)
145 -- Return component encoding for specified components.
146 -- - jpcrr.component_decode(string line)
147 -- Return component decoding for specified line, nil/nil if it doesn't encode
148 -- anything, nil/string if parse error occurs (the error is the second return).
149 -- - jpcrr.save_state(string name)
150 -- Savestate into specified file. Returns name used.
151 -- - jpcrr.save_movie(string name)
152 -- Save movie into specified file. Returns name used.
153 -- - jpcrr.load_state_normal(string name)
154 -- Load specified savestate. Returns name used.
155 -- - jpcrr.load_state_preserve_events(string name)
156 -- Load specified savestate, preserving events. Returns name used.
157 -- - jpcrr.load_state_movie(string name)
158 -- Load specified savestate as movie. Returns name used.
159 -- - jpcrr.assemble()
160 -- Open system settings dialog.
161 -- - jpcrr.change_authors()
162 -- Open change authors dialog.
163 -- - jpcrr.exit = function()
164 -- Exit the Lua VM.
165 -- - jpcrr.ram_dump(string name, boolean binary)
166 -- Dump PC memory to specified file. If binary is true, dump is binary, otherwise
167 -- textual hexadecimal dump.
168 -- - jpcrr.write_byte(number addr, number value)
169 -- Write byte to specified physical address.
170 -- - jpcrr.write_word(number addr, number value)
171 -- Write word to specified physical address (little endian).
172 -- - jpcrr.write_dword(number addr, number value)
173 -- Write dword to specified physical address (little endian).
174 -- - jpcrr.read_byte(number addr)
175 -- Return byte from specified physical address.
176 -- - jpcrr.read_word(number addr)
177 -- Return word from specified physical address (little endian).
178 -- - jpcrr.read_dword(number addr)
179 -- Return dword from specified physical address (little endian).
180 -- - jpcrr.read_byte_signed(number addr)
181 -- Return signed byte from specified physical address.
182 -- - jpcrr.read_word_signed(number addr)
183 -- Return signed word from specified physical address (little endian).
184 -- - jpcrr.read_dword_signed(number addr)
185 -- Return signed dword from specified physical address (little endian).
186 -- - jpcrr.timed_trap(number nsecs)
187 -- Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
188 -- - jpcrr.vretrace_start_trap(boolean is_on)
189 -- Set trap on vretrace start on/off.
190 -- - jpcrr.vretrace_end_trap(boolean is_on)
191 -- Set trap on vretrace end on/off.
192 -- - jpcrr.pc_start()
193 -- Start PC execution.
194 -- - jpcrr.pc_stop()
195 -- Stop PC execution.
196 -- - jpcrr.set_pccontrol_pos(number x, number y)
197 -- Set position of PCControl window.
198 -- - jpcrr.set_luaplugin_pos(number x, number y)
199 -- Set position of LuaPlugin window.
200 -- - jpcrr.set_pcmonitor_pos(number x, number y)
201 -- Set position of PCMonitor window.
202 -- - jpcrr.set_pcstartstoptest_pos(number x, number y)
203 -- Set position of PCStartStopTest window.
204 -- - jpcrr.set_virtualkeyboard_pos(number x, number y)
205 -- Set position of VirtualKeyboard window.
206 -- - jpcrr.stringlessthan(String x, String y)
207 -- Return true if x is before y in codepoint lexical order, otherwise false.
208 -- - jpcrr.screenshot(boolean include_hud)
209 -- Take screen shot (Requires monitor). If include_hud is true, include HUD
210 -- (as shown on screen). Note that this should only be called during frame
211 -- hold or results are pretty much undefined.
212 -- - jpcrr.sendevent(string/number...)
213 -- Sends specified event.
214 -- - jpcrr.movie_rerecords()
215 -- Return number of rerecords (nil if no movie loaded).
216 -- - jpcrr.movie_length()
217 -- Return length of movie in ns (nil if no movie loaded).
218 -- - jpcrr.movie_headers()
219 -- Return headers of movie as array of arrays (nil if no movie loaded).
221 -- I/O functions have the following conventions. If function returns any real data, the first
222 -- return value returns this data or is nil. Otherwise first return value is true or false.
223 -- If first return value is nil or false, then the second return value gives textual error
224 -- message for failed operation, or is nil if EOF occured before anything was read.
226 -- Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
227 -- success or failure.
229 -- Specifying nil as name of file results random filename being used (it even works with unlink,
230 -- mkdir, rename and read-only access, but doesn't make any sense there).
232 -- Class: BinaryFile:
233 -- Binary file for RO or RW access. Methods are as follows:
234 -- - name()
235 -- Return name of file.
236 -- - length()
237 -- Return length of file.
238 -- - set_length(number length)
239 -- Truncate file to specified length
240 -- - read(number offset, number length)
241 -- Read up to length bytes from offset.
242 -- - write(number offset, string content)
243 -- Write content to specified offset.
244 -- - close()
245 -- Close the file.
246 -- Class: BinaryInput:
247 -- Binary file for sequential input. Methods are as follows:
248 -- - name()
249 -- Return name of file.
250 -- - four_to_five()
251 -- Return BinaryInput that is four to five decoding of this stream.
252 -- - text()
253 -- Return stream as TextInput.
254 -- - inflate()
255 -- Return BinaryInput that is inflate of this stream.
256 -- - read(number bytes)
257 -- Read up to bytes bytes from file.
258 -- - read()
259 -- Read the entiere file at once.
260 -- - close()
261 -- Close the file.
262 -- Character set for binary files is Latin-1.
264 -- Class: BinaryOutput:
265 -- Binary file for sequential output. Methods are as follows:
266 -- - name()
267 -- Return name of file.
268 -- - four_to_five()
269 -- Return BinaryOutput that writes four to five encoded output to this stream.
270 -- - text()
271 -- Return stream as TextOutput.
272 -- - deflate()
273 -- Return BinaryOutput that writes deflate output to this stream.
274 -- - write(string content)
275 -- Write string to file.
276 -- - close()
277 -- Close the file.
278 -- Character set for binary files is Latin-1.
280 -- Class: TextInput:
281 -- - name()
282 -- Return name of file.
283 -- - read()
284 -- Read line from file.
285 -- - read_component()
286 -- Read next componented line into array.
287 -- - lines()
288 -- Line iterator function.
289 -- - close()
290 -- Close the file.
291 -- Character set for text files is UTF-8.
293 -- Class: TextOutput:
294 -- - name()
295 -- Return name of file.
296 -- - write(string line)
297 -- Write line line to file.
298 -- - write_component(table components)
299 -- Write componented line.
300 -- - close()
301 -- Close the file.
302 -- Character set for text files is UTF-8.
304 -- Class ArchiveIn:
305 -- - member(string name)
306 -- Open substream for member name. The methods are the same as for io.opentextin.
307 -- - member_binary(string name)
308 -- Open binary (four to five) substream for member name. The methods are the same as
309 -- for io.openbinaryin.
310 -- - close()
311 -- Close the file. Any opened substreams are invalidated.
312 -- - member_list()
313 -- Return table listing all members of archive (sorted by name).
314 -- Class ArchiveOut:
315 -- - member(string name)
316 -- Open substream for member name. The methods are the same as for io.opentextout. Note that
317 -- previous member must be closed before next can open.
318 -- - member_binary(string name)
319 -- Open binary (four to five) substream for member name. The methods are the same as
320 -- for io.openbinaryout. Note that previous substream must be closed before next can open.
321 -- - commit()
322 -- Commit the file. No substream may be open. Closes the file.
323 -- - rollback()
324 -- Rollback the file. No substream may be open. Closes the file.
326 -- - io.open(string name, string mode) -> BinaryFile
327 -- Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
328 -- write).
329 -- - io.open_read(string name) -> BinaryInput
330 -- Open file named @name as binary input stream.
331 -- - io.open_write(string name) -> BinaryOutput
332 -- Open file named @name as binary input stream.
333 -- - io.open_arch_read(string name) -> ArchiveIn
334 -- Open file named @name as input archive.
335 -- - io.open_arch_write(string name) -> ArchiveOut
336 -- Open file named @name as output archive.
337 -- - io.mkdir(string name)
338 -- Create directory name. Returns name created on success, nil on failure.
339 -- - io.unlink(string name)
340 -- Delete file/directory name. Returns name deleted on success, nil on failure.
341 -- - io.rename(string old, string new)
342 -- Rename file old -> new. Returns old, new on success, nil on failure.
343 -- - io.transform.text()
344 -- Returns function that calls text() method of its parameter.
345 -- - io.transform.four_to_five()
346 -- Returns function that calls four_to_five() method of its parameter.
347 -- - io.transform.deflate()
348 -- Returns function that calls deflate() method of its parameter.
349 -- - io.transform.inflate()
350 -- Returns function that calls inflate() method of its parameter.
351 -- - io.dotransform(object obj, function...)
352 -- Call specified functions on specified object. If any function fails (first argument nil
353 -- or false), call close method on preceeding object. Otherwise call specified functions
354 -- chained left to right and return the result.
355 -- - io.dotransform2(object obj, string err, function...)
356 -- Similar to dotransform except if obj is nil or false, returns obj, err.
362 local handle, err, chunk, indication, k, v;
364 local loadmod = loadmodule;
365 loadmodule = nil;
367 local export_module_in = function(tab, modname, prefix)
368 local fun = loadmod(modname);
369 for k, v in pairs(fun) do
370 tab[(prefix or "") .. k] = v;
374 jpcrr = {};
375 jpcrr.hud = {};
376 bit = {};
377 io = {};
379 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
380 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
381 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
382 export_module_in(bit, "org.jpc.luaextensions.Bitops");
384 -- Few misc functions.
385 assert = function(val, err)
386 if (not val) and err then
387 error(err);
389 return val;
392 modulus_split = function(number, ...)
393 local dividers = {...};
394 local results = {};
395 local rem;
397 for k, v in ipairs(dividers) do
398 rem = number % v;
399 table.insert(results, (number - rem) / v);
400 number = rem;
403 table.insert(results, number);
404 return unpack(results);
407 local getmtable = getmetatable;
408 local toString = tostring;
409 local inject_binary_file;
410 local inject_binary_input;
411 local inject_binary_output;
412 local inject_text_input;
413 local inject_text_output;
414 local inject_archive_input;
415 local inject_archive_output;
417 -- Class member injectors.
418 inject_binary_file = function(obj, name)
419 local _name = name;
420 getmtable(obj).name = function(obj)
421 return _name;
423 getmtable(obj).__index = function(tab, name)
424 local x = getmtable(obj)[name];
425 if x then
426 return x;
428 error("Invalid method " .. name .. " for BinaryFile");
430 return obj;
433 inject_binary_input = function(obj, underlying, name)
434 local _name = name;
435 local old_four_to_five = getmtable(obj).four_to_five;
436 local old_inflate = getmtable(obj).inflate;
437 local old_text = getmtable(obj).text;
438 local old_read = getmtable(obj).read;
439 local old_close = getmtable(obj).close;
440 local underlying_object = underlying;
442 getmtable(obj).name = function(obj)
443 return _name;
445 getmtable(obj).four_to_five = function(obj)
446 local res, err;
447 res, err = old_four_to_five(obj);
448 if not res then
449 return res, err;
451 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
453 getmtable(obj).inflate = function(obj)
454 local res, err;
455 res, err = old_inflate(obj);
456 if not res then
457 return res, err;
459 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
461 getmtable(obj).text = function(obj)
462 local res, err;
463 res, err = old_text(obj);
464 if not res then
465 return res, err;
467 return inject_text_input(res, obj, "text<" .. _name .. ">");
469 getmtable(obj).read = function(obj, toread)
470 if toread then
471 return old_read(obj, toread);
472 else
473 local res = "";
474 local ret, err;
475 while true do
476 ret, err = old_read(obj, 16384);
477 if not ret then
478 if not err then
479 return res;
481 return nil, err;
483 res = res .. ret;
487 getmtable(obj).close = function(obj)
488 local ret, err, ret2, err2;
489 ret, err = old_close(obj);
490 if underlying_object then ret2, err2 = underlying_object:close(); end
491 if ret and not ret2 then
492 err = err2;
493 ret = ret2;
495 return ret, err;
497 getmtable(obj).__index = function(tab, name)
498 local x = getmtable(obj)[name];
499 if x then
500 return x;
502 error("Invalid method " .. name .. " for BinaryInput");
504 return obj;
507 inject_binary_output = function(obj, underlying, name)
508 local _name = name;
509 local old_four_to_five = getmtable(obj).four_to_five;
510 local old_deflate = getmtable(obj).deflate;
511 local old_text = getmtable(obj).text;
512 local old_close = getmtable(obj).close;
513 local underlying_object = underlying;
515 getmtable(obj).name = function(obj)
516 return _name;
518 getmtable(obj).four_to_five = function(obj)
519 local res, err;
520 res, err = old_four_to_five(obj);
521 if not res then
522 return res, err;
524 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
526 getmtable(obj).deflate = function(obj)
527 local res, err;
528 res, err = old_deflate(obj);
529 if not res then
530 return res, err;
532 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
534 getmtable(obj).text = function(obj)
535 local res, err;
536 res, err = old_text(obj);
537 if not res then
538 return res, err;
540 return inject_text_output(res, obj, "text<" .. _name .. ">");
542 getmtable(obj).close = function(obj)
543 local ret, err, ret2, err2;
544 ret, err = old_close(obj);
545 if underlying_object then ret2, err2 = underlying_object:close(); end
546 if ret and not ret2 then
547 err = err2;
548 ret = ret2;
550 return ret, err;
552 getmtable(obj).__index = function(tab, name)
553 local x = getmtable(obj)[name];
554 if x then
555 return x;
557 error("Invalid method " .. name .. " for BinaryOutput");
559 return obj;
562 inject_text_input = function(obj, underlying, name)
563 local _name = name;
564 local old_close = getmtable(obj).close;
565 local underlying_object = underlying;
567 getmtable(obj).lines = function(obj)
568 return function(state, prevline)
569 return state:read();
570 end, obj, nil;
572 getmtable(obj).name = function(obj)
573 return _name;
575 getmtable(obj).close = function(obj)
576 local ret, err, ret2, err2;
577 ret, err = old_close(obj);
578 if underlying_object then ret2, err2 = underlying_object:close(); end
579 if ret and not ret2 then
580 err = err2;
581 ret = ret2;
583 return ret, err;
585 getmtable(obj).__index = function(tab, name)
586 local x = getmtable(obj)[name];
587 if x then
588 return x;
590 error("Invalid method " .. name .. " for TextInput");
592 return obj;
595 inject_text_output = function(obj, underlying, name)
596 local _name = name;
597 local old_close = getmtable(obj).close;
598 local underlying_object = underlying;
600 getmtable(obj).name = function(obj)
601 return _name;
603 getmtable(obj).close = function(obj)
604 local ret, err, ret2, err2;
605 ret, err = old_close(obj);
606 if underlying_object then ret2, err2 = underlying_object:close(); end
607 if ret and underlying_object then
608 err = err2;
609 ret = ret2;
611 return ret, err;
613 getmtable(obj).__index = function(tab, name)
614 local x = getmtable(obj)[name];
615 if x then
616 return x;
618 error("Invalid method " .. name .. " for TextOutput");
620 return obj;
623 inject_archive_input = function(obj, name)
624 local _name = name;
625 local old_member = getmtable(obj).member;
626 local old_member_list = getmtable(obj).member_list;
627 getmtable(obj).member = function(obj, member)
628 local res, err;
629 res, err = old_member(obj, member);
630 if not res then
631 return res, err;
633 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
635 getmtable(obj).name = function(obj)
636 return _name;
638 getmtable(obj).member_list = function(obj)
639 local tab = old_member_list(obj);
640 if tab then table.sort(tab, jpcrr.stringlessthan); end
641 return tab;
643 getmtable(obj).__index = function(tab, name)
644 local x = getmtable(obj)[name];
645 if x then
646 return x;
648 error("Invalid method " .. name .. " for ArchiveInput");
650 return obj;
653 inject_archive_output = function(obj, name)
654 local _name = name;
655 local old_member = getmtable(obj).member;
656 getmtable(obj).member = function(obj, member)
657 local res, err;
658 res, err = old_member(obj, member);
659 if not res then
660 return res, err;
662 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
664 getmtable(obj).name = function(obj)
665 return _name;
667 getmtable(obj).__index = function(tab, name)
668 local x = getmtable(obj)[name];
669 if x then
670 return x;
672 error("Invalid method " .. name .. " for ArchiveOutput");
674 return obj;
678 -- Redefined print.
680 local rprint = print_console_msg;
681 print_console_msg = nil;
682 print = function(...)
683 local x = "";
684 local y = {...};
685 local i;
686 for i = 1,#y do
687 if i > 1 then
688 x = x .. "\t" .. toString(y[i]);
689 else
690 x = toString(y[i]);
693 rprint(x);
695 print_console_msg = nil;
698 -- I/O routines.
699 local stringfind = string.find;
700 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
701 local path = args["luapath"] or ".";
702 local toresourcename = function(resname)
703 if not resname then
704 return randname(path .. "/", "luatemp-");
707 if not stringfind(resname, "[%d%l%u_%-]") then
708 error("Bad resource name (case 1): " .. resname);
710 if stringfind(resname, "^/") then
711 error("Bad resource name (case 2): " .. resname);
713 if stringfind(resname, "%.%.") then
714 error("Bad resource name (case 3): " .. resname);
716 if stringfind(resname, "\\") then
717 error("Bad resource name (case 4): " .. resname);
720 return resname, path .. "/" .. resname;
725 local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
726 local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
727 local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
728 local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
729 local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
731 local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
732 local mkdir = baseFS.mkdir;
733 local unlink = baseFS.unlink;
734 local rename = baseFS.rename;
736 local getmtable = getmetatable;
738 loadfile = function(_script)
739 local file, file2, err, content;
740 local x, y;
741 x, y = toresourcename(_script);
742 file, err = openbinin(y, "r");
743 if not file then
744 return nil, "Can't open " .. _script .. ": " .. err;
746 file2, err = file:text();
747 if not file2 then
748 return nil, "Can't transform " .. _script .. ": " .. err;
750 content = "";
751 line = file2:read();
752 while line do
753 content = content .. line .. "\n";
754 line = file2:read();
756 file2:close();
757 file:close();
758 return loadstring(content, _script);
761 io.open = function(name, mode)
762 local _name;
763 local res, err;
764 local y;
765 _name, y = toresourcename(name);
766 res, err = openbinary(y, mode);
767 if not res then
768 return res, err;
770 return inject_binary_file(res, _name);
773 io.open_arch_read = function(name)
774 local _name = name;
775 local res, err;
776 local y;
777 _name, y = toresourcename(name);
778 res, err = openarchin(y);
779 if not res then
780 return res, err;
782 return inject_archive_input(res, _name);
785 io.open_arch_write = function(name)
786 local _name = name;
787 local res, err;
788 local y;
789 _name, y = toresourcename(name);
790 res, err = openarchout(y);
791 if not res then
792 return res, err;
794 return inject_archive_output(res, _name);
797 io.open_read = function(name)
798 local _name = name;
799 local res, err;
800 local y;
801 _name, y = toresourcename(name);
802 res, err = openbinin(y);
803 if not res then
804 return res, err;
806 return inject_binary_input(res, nil, _name);
809 io.open_write = function(name)
810 local _name = name;
811 local res, err;
812 local y;
813 _name, y = toresourcename(name);
814 res, err = openbinout(y);
815 if not res then
816 return res, err;
818 return inject_binary_output(res, nil, _name);
821 io.mkdir = function(name)
822 local _name, y;
823 _name, y = toresourcename(name);
824 if mkdir(y) then
825 return _name;
826 else
827 return nil;
831 io.unlink = function(name)
832 local _name, y;
833 _name, y = toresourcename(name);
834 if unlink(y) then
835 return _name;
836 else
837 return nil;
841 io.rename = function(name1, name2)
842 local _name, y;
843 local _name2, y2;
844 _name, y = toresourcename(name1);
845 _name2, y2 = toresourcename(name2);
846 if rename(y, y2) then
847 return _name, _name2;
848 else
849 return nil;
853 io.transform = {};
855 io.transform.text = function()
856 return function(obj)
857 return obj:text();
861 io.transform.four_to_five = function()
862 return function(obj)
863 return obj:four_to_five();
867 io.transform.inflate = function()
868 return function(obj)
869 return obj:inflate();
873 io.transform.deflate = function()
874 return function(obj)
875 return obj:deflate();
879 io.dotransform = function(obj, ...)
880 local todo = {...};
881 local k, v;
882 local obj2, err;
883 for k, v in ipairs(todo) do
884 obj2, err = v(obj);
885 if not obj2 then
886 obj:close();
887 return nil, err;
889 obj = obj2;
891 return obj;
894 io.dotransform2 = function(obj, err, ...)
895 if not obj then
896 return obj, err;
898 return io.dotransform(obj, err, ...);
903 jpcrr.next_frame = function(name)
904 while true do
905 if not jpcrr.pc_connected() then
906 jpcrr.wait_pc_attach();
908 if jpcrr.in_frame_hold() then
909 jpcrr.release_vga();
911 if jpcrr.wait_vga() then
912 return;
918 -- Various stuff built on top of ECI.
919 local invoke = jpcrr.invoke;
920 local invokecall = jpcrr.call;
921 local invokesync = jpcrr.invoke_synchronous;
923 jpcrr.sendevent = function(...)
924 local arguments = {...};
925 local k, v;
926 for k, v in ipairs(arguments) do
927 arguments[k] = toString(v);
929 invokesync("sendevent", arguments);
932 jpcrr.save_state = function(name)
933 local _name, _fname;
934 _name, _fname = toresourcename(name);
935 invokesync("state-save", {_fname});
936 return _name;
939 jpcrr.save_movie = function(name)
940 local _name, _fname;
941 _name, _fname = toresourcename(name);
942 invokesync("movie-save", {_name});
943 return _name;
946 jpcrr.load_state_normal = function(name)
947 local _name, _fname;
948 _name, _fname = toresourcename(name);
949 invokesync("state-load", {_name});
950 return _name;
953 jpcrr.load_state_preserve_events = function(name)
954 local _name, _fname;
955 _name, _fname = toresourcename(name);
956 invokesync("state-load-noevents", {_name});
957 return _name;
960 jpcrr.load_state_movie = function(name)
961 local _name, _fname;
962 _name, _fname = toresourcename(name);
963 invokesync("state-load-movie", {_name});
964 return _name;
967 jpcrr.assemble = function()
968 invokesync("pc-assemble");
971 jpcrr.change_authors = function()
972 invokesync("change-authors");
975 jpcrr.ram_dump = function(name, binary)
976 local _name, _fname;
977 _name, _fname = toresourcename(name);
978 if binary then
979 invokesync("ram-dump-binary", {_name});
980 else
981 invokesync("ram-dump-text", {_name});
983 return _name;
986 jpcrr.hud.left_gap = function(f, g)
987 invoke("hud-left-gap", {toString(f), toString(g)});
990 jpcrr.hud.right_gap = function(f, g)
991 invoke("hud-right-gap", {toString(f), toString(g)});
994 jpcrr.hud.top_gap = function(f, g)
995 invoke("hud-top-gap", {toString(f), toString(g)});
998 jpcrr.hud.bottom_gap = function(f, g)
999 invoke("hud-bottom-gap", {toString(f), toString(g)});
1002 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
1003 invoke("hud-white-solid-box", {toString(f), toString(x), toString(y), toString(w), toString(h)});
1006 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
1007 invoke("hud-box", {toString(f), toString(x), toString(y), toString(w), toString(h),
1008 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
1009 toString(fg), tostring(fb), toString(fa)});
1012 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1013 invoke("hud-circle", {toString(f), toString(x), toString(y), toString(r),
1014 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
1015 toString(fg), tostring(fb), toString(fa)});
1018 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1019 invoke("hud-bitmap", {toString(f), toString(x), toString(y), bmap, toString(lr),
1020 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
1021 toString(fa)});
1024 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1025 invoke("hud-bitmap-binary", {toString(f), toString(x), toString(y), bmap, toString(lr),
1026 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
1027 toString(fa)});
1030 jpcrr.set_pccontrol_pos = function(x, y)
1031 invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
1034 jpcrr.set_luaplugin_pos = function(x, y)
1035 invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
1038 jpcrr.set_pcmonitor_pos = function(x, y)
1039 invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
1042 jpcrr.set_pcstartstoptest_pos = function(x, y)
1043 invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
1046 jpcrr.set_virtualkeyboard_pos = function(x, y)
1047 invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
1050 jpcrr.exit = function()
1051 invokesync("luaplugin-terminate");
1054 jpcrr.pc_start = function()
1055 invoke("pc-start");
1058 jpcrr.pc_stop = function()
1059 invokesync("pc-stop");
1062 jpcrr.screenshot = function(include_hud)
1063 if include_hud then
1064 invoke("screenshot-renderbuffer");
1065 else
1066 invoke("screenshot-vgabuffer");
1071 jpcrr.vretrace_start_trap = function(is_on)
1072 if is_on then
1073 invokesync("trap-vretrace-start-on");
1074 else
1075 invokesync("trap-vretrace-start-off");
1079 jpcrr.vretrace_end_trap = function(is_on)
1080 if is_on then
1081 invokesync("trap-vretrace-end-on");
1082 else
1083 invokesync("trap-vretrace-end-off");
1087 jpcrr.timed_trap = function(nsecs)
1088 if nsecs then
1089 invokesync("trap-timed", {toString(nsecs)});
1090 else
1091 invokesync("trap-timed-disable");
1095 jpcrr.write_byte = function(addr, value)
1096 invokesync("memory-write", {toString(addr), toString(value), "1"});
1099 jpcrr.write_word = function(addr, value)
1100 invokesync("memory-write", {toString(addr), toString(value), "2"});
1103 jpcrr.write_dword = function(addr, value)
1104 invokesync("memory-write", {toString(addr), toString(value), "4"});
1107 jpcrr.read_byte = function(addr)
1108 local t = {toString(addr), "1"};
1109 t = invokecall("memory-read", t);
1110 return (t or {})[1];
1113 jpcrr.read_word = function(addr)
1114 local t = {toString(addr), "2"};
1115 t = invokecall("memory-read", t);
1116 return (t or {})[1];
1119 jpcrr.read_dword = function(addr)
1120 local t = {toString(addr), "4"};
1121 t = invokecall("memory-read", t);
1122 return (t or {})[1];
1125 jpcrr.read_byte_signed = function(addr)
1126 local t = {toString(addr), "1"};
1127 t = invokecall("memory-read", t);
1128 return bit.tosigned((t or {})[1], 7);
1131 jpcrr.read_word_signed = function(addr)
1132 local t = {toString(addr), "2"};
1133 t = invokecall("memory-read", t);
1134 return bit.tosigned((t or {})[1], 15);
1137 jpcrr.read_dword_signed = function(addr)
1138 local t = {toString(addr), "4"};
1139 t = invokecall("memory-read", t);
1140 return bit.tosigned((t or {})[1], 31);
1143 jpcrr.invoke = nil;
1144 jpcrr.invoke_synchronous = nil;
1145 jpcrr.call = null
1147 -- Dofile.
1148 dofile = function(_script)
1149 local chunk, err, indication
1150 chunk, err = loadfile(_script);
1151 if not chunk then
1152 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1154 return chunk();
1157 local args2 = args;
1158 args = null;
1159 args = {};
1160 for k, v in pairs(args2) do
1161 if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1162 args[string.sub(k, 3)] = v;
1165 jpcrr_raw = null;
1168 chunk = null;
1169 loaded, err = pcall(function()
1170 chunk, err = loadfile(script);
1171 if not chunk then
1172 error(err);
1174 end);
1175 if not loaded then
1176 print("Kernel: Can't load script " .. script .. ": " .. err);
1177 invoke("luaplugin-terminate");
1178 while true do end
1181 script = null;
1182 indication, err = pcall(chunk);
1183 if not indication then
1184 print("Kernel: Unprotected error in script: " .. err);
1185 invoke("luaplugin-terminate");
1186 while true do end