Add ability for Lua to query movie length, rerecord count and headers
[jpcrr.git] / luakernel.lua
blob18615610388599eaffe41b675ad31a0448ae185d
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.tohex(number num)
51 -- Returns hexadecimal string representation of number.
52 -- - jpcrr.wait_message()
53 -- Waits for message (string) to come from message queue. Reutrns nil if interrupted.
54 -- - jpcrr.poll_message()
55 -- Checks if there is message from message queue. Reutrns message if there is one,
56 -- nil if none.
57 -- - jpcrr.wait_pc_stop()
58 -- Waits for PC execution to stop (but does not attempt to actually stop it).
59 -- If script is in frame hold, the frame hold is released.
60 -- Returns true if execution got stopped, false if interrupted.
61 -- - jpcrr.pc_running()
62 -- Returns true if PC is running.
63 -- - jpcrr.clock_time()
64 -- Returns current time or nil if no PC.
65 -- - jpcrr.pc_connected()
66 -- Returns true if PC is connected.
67 -- - jpcrr.wait_pc_attach()
68 -- Wait for PC to attach.
69 -- - jpcrr.next_frame()
70 -- Wait for next frame output hold.
71 -- - jpcrr.in_frame_hold()
72 -- Returns true if in frame hold, false otherwise.
73 -- - jpcrr.keypressed(number key)
74 -- Return true if key is pressed, else false.
75 -- - jpcrr.wait_vga()
76 -- Waits for VGA to enter frame hold mode. Frame hold happens once per frame.
77 -- - jpcrr.release_vga()
78 -- Allow VGA to exit frame hold mode. Wait for frame hold first.
79 -- - jpcrr.vga_resolution()
80 -- Return VGA x and y resolutions. -1x-1 or 0x0 is returned if no valid resolution.
81 -- Should only be called during frame hold.
82 -- - jpcrr.hud.left_gap(number flags, number gap)
83 -- Set left gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
84 -- 1 (2) is set, dump to video dump.
85 -- - jpcrr.hud.right_gap(number flags, number gap)
86 -- Set right gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
87 -- 1 (2) is set, dump to video dump.
88 -- - jpcrr.hud.top_gap(number flags, number gap)
89 -- Set top gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
90 -- 1 (2) is set, dump to video dump.
91 -- - jpcrr.hud.bottom_gap(number flags, number gap)
92 -- Set bottom gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
93 -- 1 (2) is set, dump to video dump.
94 -- - jpcrr.hud.white_solid_box(number flags, number x, number y, number w, number h)
95 -- Draw with solid opaque box.
96 -- - jpcrr.hud.box(number flags, number x, number y, number w, number h, number linethick,
97 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
98 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
99 -- Draw box with specified size, border line thickness, line color and fill color.
100 -- - jpcrr.hud.circle(number flags, number x, number y, number r, number linethick,
101 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
102 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
103 -- Draw circle with specified size, border line thickness, line color and fill color.
104 -- - jpcrr.hud.bitmap(number flags, number x, number y, string bmap,
105 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
106 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
107 -- Draw bitmap with specified foreground color and background color.
108 -- - jpcrr.hud.bitmap_binary(number flags, number x, number y, string bmap,
109 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
110 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
111 -- Draw binary bitmap with specified foreground color and background color.
112 -- - jpcrr.joystick_state()
113 -- Returns nil if no joystick. Otherwise returns hold times for all four axis (numeric)
114 -- followed by button states (boolean).
115 -- - jpcrr.keyboard_leds()
116 -- Returns nil if no keyboard, false if LED status is unknown. Otherwise returns three
117 -- booleans, first being state of num lock, second being state of caps lock and third
118 -- being state of scroll lock.
119 -- - jpcrr.mouse_state()
120 -- Returns nil if no mouse. Otherwise returns X, Y and Z axis pending motions (numeric)
121 -- followed by button states (5 booleans).
122 -- - jpcrr.component_encode(table components)
123 -- Return component encoding for specified components.
124 -- - jpcrr.component_decode(string line)
125 -- Return component decoding for specified line, nil/nil if it doesn't encode
126 -- anything, nil/string if parse error occurs (the error is the second return).
127 -- - jpcrr.save_state(string name)
128 -- Savestate into specified file. Returns name used.
129 -- - jpcrr.save_movie(string name)
130 -- Save movie into specified file. Returns name used.
131 -- - jpcrr.load_state_normal(string name)
132 -- Load specified savestate. Returns name used.
133 -- - jpcrr.load_state_preserve_events(string name)
134 -- Load specified savestate, preserving events. Returns name used.
135 -- - jpcrr.load_state_movie(string name)
136 -- Load specified savestate as movie. Returns name used.
137 -- - jpcrr.assemble()
138 -- Open system settings dialog.
139 -- - jpcrr.change_authors()
140 -- Open change authors dialog.
141 -- - jpcrr.exit = function()
142 -- Exit the Lua VM.
143 -- - jpcrr.ram_dump(string name, boolean binary)
144 -- Dump PC memory to specified file. If binary is true, dump is binary, otherwise
145 -- textual hexadecimal dump.
146 -- - jpcrr.write_byte(number addr, number value)
147 -- Write byte to specified physical address.
148 -- - jpcrr.write_word(number addr, number value)
149 -- Write word to specified physical address (little endian).
150 -- - jpcrr.write_dword(number addr, number value)
151 -- Write dword to specified physical address (little endian).
152 -- - jpcrr.read_byte(number addr)
153 -- Return byte from specified physical address.
154 -- - jpcrr.read_word(number addr)
155 -- Return word from specified physical address (little endian).
156 -- - jpcrr.read_dword(number addr)
157 -- Return dword from specified physical address (little endian).
158 -- - jpcrr.timed_trap(number nsecs)
159 -- Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
160 -- - jpcrr.vretrace_start_trap(boolean is_on)
161 -- Set trap on vretrace start on/off.
162 -- - jpcrr.vretrace_end_trap(boolean is_on)
163 -- Set trap on vretrace end on/off.
164 -- - jpcrr.pc_start()
165 -- Start PC execution.
166 -- - jpcrr.pc_stop()
167 -- Stop PC execution.
168 -- - jpcrr.set_pccontrol_pos(number x, number y)
169 -- Set position of PCControl window.
170 -- - jpcrr.set_luaplugin_pos(number x, number y)
171 -- Set position of LuaPlugin window.
172 -- - jpcrr.set_pcmonitor_pos(number x, number y)
173 -- Set position of PCMonitor window.
174 -- - jpcrr.set_pcstartstoptest_pos(number x, number y)
175 -- Set position of PCStartStopTest window.
176 -- - jpcrr.set_virtualkeyboard_pos(number x, number y)
177 -- Set position of VirtualKeyboard window.
178 -- - jpcrr.stringlessthan(String x, String y)
179 -- Return true if x is before y in codepoint lexical order, otherwise false.
180 -- - jpcrr.screenshot(boolean include_hud)
181 -- Take screen shot (Requires monitor). If include_hud is true, include HUD
182 -- (as shown on screen). Note that this should only be called during frame
183 -- hold or results are pretty much undefined.
184 -- - jpcrr.sendevent(string/number...)
185 -- Sends specified event.
186 -- - jpcrr.movie_rerecords()
187 -- Return number of rerecords (nil if no movie loaded).
188 -- - jpcrr.movie_length()
189 -- Return length of movie in ns (nil if no movie loaded).
190 -- - jpcrr.movie_headers()
191 -- Return headers of movie as array of arrays (nil if no movie loaded).
193 -- I/O functions have the following conventions. If function returns any real data, the first
194 -- return value returns this data or is nil. Otherwise first return value is true or false.
195 -- If first return value is nil or false, then the second return value gives textual error
196 -- message for failed operation, or is nil if EOF occured before anything was read.
198 -- Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
199 -- success or failure.
201 -- Specifying nil as name of file results random filename being used (it even works with unlink,
202 -- mkdir, rename and read-only access, but doesn't make any sense there).
204 -- Class: BinaryFile:
205 -- Binary file for RO or RW access. Methods are as follows:
206 -- - name()
207 -- Return name of file.
208 -- - length()
209 -- Return length of file.
210 -- - set_length(number length)
211 -- Truncate file to specified length
212 -- - read(number offset, number length)
213 -- Read up to length bytes from offset.
214 -- - write(number offset, string content)
215 -- Write content to specified offset.
216 -- - close()
217 -- Close the file.
218 -- Class: BinaryInput:
219 -- Binary file for sequential input. Methods are as follows:
220 -- - name()
221 -- Return name of file.
222 -- - four_to_five()
223 -- Return BinaryInput that is four to five decoding of this stream.
224 -- - text()
225 -- Return stream as TextInput.
226 -- - inflate()
227 -- Return BinaryInput that is inflate of this stream.
228 -- - read(number bytes)
229 -- Read up to bytes bytes from file.
230 -- - read()
231 -- Read the entiere file at once.
232 -- - close()
233 -- Close the file.
234 -- Character set for binary files is Latin-1.
236 -- Class: BinaryOutput:
237 -- Binary file for sequential output. Methods are as follows:
238 -- - name()
239 -- Return name of file.
240 -- - four_to_five()
241 -- Return BinaryOutput that writes four to five encoded output to this stream.
242 -- - text()
243 -- Return stream as TextOutput.
244 -- - deflate()
245 -- Return BinaryOutput that writes deflate output to this stream.
246 -- - write(string content)
247 -- Write string to file.
248 -- - close()
249 -- Close the file.
250 -- Character set for binary files is Latin-1.
252 -- Class: TextInput:
253 -- - name()
254 -- Return name of file.
255 -- - read()
256 -- Read line from file.
257 -- - read_component()
258 -- Read next componented line into array.
259 -- - lines()
260 -- Line iterator function.
261 -- - close()
262 -- Close the file.
263 -- Character set for text files is UTF-8.
265 -- Class: TextOutput:
266 -- - name()
267 -- Return name of file.
268 -- - write(string line)
269 -- Write line line to file.
270 -- - write_component(table components)
271 -- Write componented line.
272 -- - close()
273 -- Close the file.
274 -- Character set for text files is UTF-8.
276 -- Class ArchiveIn:
277 -- - member(string name)
278 -- Open substream for member name. The methods are the same as for io.opentextin.
279 -- - member_binary(string name)
280 -- Open binary (four to five) substream for member name. The methods are the same as
281 -- for io.openbinaryin.
282 -- - close()
283 -- Close the file. Any opened substreams are invalidated.
284 -- - member_list()
285 -- Return table listing all members of archive (sorted by name).
286 -- Class ArchiveOut:
287 -- - member(string name)
288 -- Open substream for member name. The methods are the same as for io.opentextout. Note that
289 -- previous member must be closed before next can open.
290 -- - member_binary(string name)
291 -- Open binary (four to five) substream for member name. The methods are the same as
292 -- for io.openbinaryout. Note that previous substream must be closed before next can open.
293 -- - commit()
294 -- Commit the file. No substream may be open. Closes the file.
295 -- - rollback()
296 -- Rollback the file. No substream may be open. Closes the file.
298 -- - io.open(string name, string mode) -> BinaryFile
299 -- Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
300 -- write).
301 -- - io.open_read(string name) -> BinaryInput
302 -- Open file named @name as binary input stream.
303 -- - io.open_write(string name) -> BinaryOutput
304 -- Open file named @name as binary input stream.
305 -- - io.open_arch_read(string name) -> ArchiveIn
306 -- Open file named @name as input archive.
307 -- - io.open_arch_write(string name) -> ArchiveOut
308 -- Open file named @name as output archive.
309 -- - io.mkdir(string name)
310 -- Create directory name. Returns name created on success, nil on failure.
311 -- - io.unlink(string name)
312 -- Delete file/directory name. Returns name deleted on success, nil on failure.
313 -- - io.rename(string old, string new)
314 -- Rename file old -> new. Returns old, new on success, nil on failure.
315 -- - io.transform.text()
316 -- Returns function that calls text() method of its parameter.
317 -- - io.transform.four_to_five()
318 -- Returns function that calls four_to_five() method of its parameter.
319 -- - io.transform.deflate()
320 -- Returns function that calls deflate() method of its parameter.
321 -- - io.transform.inflate()
322 -- Returns function that calls inflate() method of its parameter.
323 -- - io.dotransform(object obj, function...)
324 -- Call specified functions on specified object. If any function fails (first argument nil
325 -- or false), call close method on preceeding object. Otherwise call specified functions
326 -- chained left to right and return the result.
327 -- - io.dotransform2(object obj, string err, function...)
328 -- Similar to dotransform except if obj is nil or false, returns obj, err.
334 local handle, err, chunk, indication, k, v;
336 local loadmod = loadmodule;
337 loadmodule = nil;
339 local export_module_in = function(tab, modname, prefix)
340 local fun = loadmod(modname);
341 for k, v in pairs(fun) do
342 tab[(prefix or "") .. k] = v;
346 jpcrr = {};
347 jpcrr.hud = {};
348 bit = {};
349 io = {};
351 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
352 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
353 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
354 export_module_in(bit, "org.jpc.luaextensions.Bitops");
356 -- Few misc functions.
357 assert = function(val, err)
358 if (not val) and err then
359 error(err);
361 return val;
364 modulus_split = function(number, ...)
365 local dividers = {...};
366 local results = {};
367 local rem;
369 for k, v in ipairs(dividers) do
370 rem = number % v;
371 table.insert(results, (number - rem) / v);
372 number = rem;
375 table.insert(results, number);
376 return unpack(results);
379 local getmtable = getmetatable;
380 local toString = tostring;
381 local inject_binary_file;
382 local inject_binary_input;
383 local inject_binary_output;
384 local inject_text_input;
385 local inject_text_output;
386 local inject_archive_input;
387 local inject_archive_output;
389 -- Class member injectors.
390 inject_binary_file = function(obj, name)
391 local _name = name;
392 getmtable(obj).name = function(obj)
393 return _name;
395 getmtable(obj).__index = function(tab, name)
396 local x = getmtable(obj)[name];
397 if x then
398 return x;
400 error("Invalid method " .. name .. " for BinaryFile");
402 return obj;
405 inject_binary_input = function(obj, underlying, name)
406 local _name = name;
407 local old_four_to_five = getmtable(obj).four_to_five;
408 local old_inflate = getmtable(obj).inflate;
409 local old_text = getmtable(obj).text;
410 local old_read = getmtable(obj).read;
411 local old_close = getmtable(obj).close;
412 local underlying_object = underlying;
414 getmtable(obj).name = function(obj)
415 return _name;
417 getmtable(obj).four_to_five = function(obj)
418 local res, err;
419 res, err = old_four_to_five(obj);
420 if not res then
421 return res, err;
423 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
425 getmtable(obj).inflate = function(obj)
426 local res, err;
427 res, err = old_inflate(obj);
428 if not res then
429 return res, err;
431 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
433 getmtable(obj).text = function(obj)
434 local res, err;
435 res, err = old_text(obj);
436 if not res then
437 return res, err;
439 return inject_text_input(res, obj, "text<" .. _name .. ">");
441 getmtable(obj).read = function(obj, toread)
442 if toread then
443 return old_read(obj, toread);
444 else
445 local res = "";
446 local ret, err;
447 while true do
448 ret, err = old_read(obj, 16384);
449 if not ret then
450 if not err then
451 return res;
453 return nil, err;
455 res = res .. ret;
459 getmtable(obj).close = function(obj)
460 local ret, err, ret2, err2;
461 ret, err = old_close(obj);
462 if underlying_object then ret2, err2 = underlying_object:close(); end
463 if ret and not ret2 then
464 err = err2;
465 ret = ret2;
467 return ret, err;
469 getmtable(obj).__index = function(tab, name)
470 local x = getmtable(obj)[name];
471 if x then
472 return x;
474 error("Invalid method " .. name .. " for BinaryInput");
476 return obj;
479 inject_binary_output = function(obj, underlying, name)
480 local _name = name;
481 local old_four_to_five = getmtable(obj).four_to_five;
482 local old_deflate = getmtable(obj).deflate;
483 local old_text = getmtable(obj).text;
484 local old_close = getmtable(obj).close;
485 local underlying_object = underlying;
487 getmtable(obj).name = function(obj)
488 return _name;
490 getmtable(obj).four_to_five = function(obj)
491 local res, err;
492 res, err = old_four_to_five(obj);
493 if not res then
494 return res, err;
496 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
498 getmtable(obj).deflate = function(obj)
499 local res, err;
500 res, err = old_deflate(obj);
501 if not res then
502 return res, err;
504 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
506 getmtable(obj).text = function(obj)
507 local res, err;
508 res, err = old_text(obj);
509 if not res then
510 return res, err;
512 return inject_text_output(res, obj, "text<" .. _name .. ">");
514 getmtable(obj).close = function(obj)
515 local ret, err, ret2, err2;
516 ret, err = old_close(obj);
517 if underlying_object then ret2, err2 = underlying_object:close(); end
518 if ret and not ret2 then
519 err = err2;
520 ret = ret2;
522 return ret, err;
524 getmtable(obj).__index = function(tab, name)
525 local x = getmtable(obj)[name];
526 if x then
527 return x;
529 error("Invalid method " .. name .. " for BinaryOutput");
531 return obj;
534 inject_text_input = function(obj, underlying, name)
535 local _name = name;
536 local old_close = getmtable(obj).close;
537 local underlying_object = underlying;
539 getmtable(obj).lines = function(obj)
540 return function(state, prevline)
541 return state:read();
542 end, obj, nil;
544 getmtable(obj).name = function(obj)
545 return _name;
547 getmtable(obj).close = function(obj)
548 local ret, err, ret2, err2;
549 ret, err = old_close(obj);
550 if underlying_object then ret2, err2 = underlying_object:close(); end
551 if ret and not ret2 then
552 err = err2;
553 ret = ret2;
555 return ret, err;
557 getmtable(obj).__index = function(tab, name)
558 local x = getmtable(obj)[name];
559 if x then
560 return x;
562 error("Invalid method " .. name .. " for TextInput");
564 return obj;
567 inject_text_output = function(obj, underlying, name)
568 local _name = name;
569 local old_close = getmtable(obj).close;
570 local underlying_object = underlying;
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 underlying_object 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 TextOutput");
592 return obj;
595 inject_archive_input = function(obj, name)
596 local _name = name;
597 local old_member = getmtable(obj).member;
598 local old_member_list = getmtable(obj).member_list;
599 getmtable(obj).member = function(obj, member)
600 local res, err;
601 res, err = old_member(obj, member);
602 if not res then
603 return res, err;
605 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
607 getmtable(obj).name = function(obj)
608 return _name;
610 getmtable(obj).member_list = function(obj)
611 local tab = old_member_list(obj);
612 if tab then table.sort(tab, jpcrr.stringlessthan); end
613 return tab;
615 getmtable(obj).__index = function(tab, name)
616 local x = getmtable(obj)[name];
617 if x then
618 return x;
620 error("Invalid method " .. name .. " for ArchiveInput");
622 return obj;
625 inject_archive_output = function(obj, name)
626 local _name = name;
627 local old_member = getmtable(obj).member;
628 getmtable(obj).member = function(obj, member)
629 local res, err;
630 res, err = old_member(obj, member);
631 if not res then
632 return res, err;
634 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
636 getmtable(obj).name = function(obj)
637 return _name;
639 getmtable(obj).__index = function(tab, name)
640 local x = getmtable(obj)[name];
641 if x then
642 return x;
644 error("Invalid method " .. name .. " for ArchiveOutput");
646 return obj;
650 -- Redefined print.
652 local rprint = print_console_msg;
653 print_console_msg = nil;
654 print = function(...)
655 local x = "";
656 local y = {...};
657 local i;
658 for i = 1,#y do
659 if i > 1 then
660 x = x .. "\t" .. toString(y[i]);
661 else
662 x = toString(y[i]);
665 rprint(x);
667 print_console_msg = nil;
670 -- I/O routines.
671 local stringfind = string.find;
672 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
673 local path = args["luapath"] or ".";
674 local toresourcename = function(resname)
675 if not resname then
676 return randname(path .. "/", "luatemp-");
679 if not stringfind(resname, "[%d%l%u_%-]") then
680 error("Bad resource name (case 1): " .. resname);
682 if stringfind(resname, "^/") then
683 error("Bad resource name (case 2): " .. resname);
685 if stringfind(resname, "%.%.") then
686 error("Bad resource name (case 3): " .. resname);
688 if stringfind(resname, "\\") then
689 error("Bad resource name (case 4): " .. resname);
692 return resname, path .. "/" .. resname;
697 local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
698 local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
699 local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
700 local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
701 local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
703 local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
704 local mkdir = baseFS.mkdir;
705 local unlink = baseFS.unlink;
706 local rename = baseFS.rename;
708 local getmtable = getmetatable;
710 loadfile = function(_script)
711 local file, file2, err, content;
712 local x, y;
713 x, y = toresourcename(_script);
714 file, err = openbinin(y, "r");
715 if not file then
716 return nil, "Can't open " .. _script .. ": " .. err;
718 file2, err = file:text();
719 if not file2 then
720 return nil, "Can't transform " .. _script .. ": " .. err;
722 content = "";
723 line = file2:read();
724 while line do
725 content = content .. line .. "\n";
726 line = file2:read();
728 file2:close();
729 file:close();
730 return loadstring(content, _script);
733 io.open = function(name, mode)
734 local _name;
735 local res, err;
736 local y;
737 _name, y = toresourcename(name);
738 res, err = openbinary(y, mode);
739 if not res then
740 return res, err;
742 return inject_binary_file(res, _name);
745 io.open_arch_read = function(name)
746 local _name = name;
747 local res, err;
748 local y;
749 _name, y = toresourcename(name);
750 res, err = openarchin(y);
751 if not res then
752 return res, err;
754 return inject_archive_input(res, _name);
757 io.open_arch_write = function(name)
758 local _name = name;
759 local res, err;
760 local y;
761 _name, y = toresourcename(name);
762 res, err = openarchout(y);
763 if not res then
764 return res, err;
766 return inject_archive_output(res, _name);
769 io.open_read = function(name)
770 local _name = name;
771 local res, err;
772 local y;
773 _name, y = toresourcename(name);
774 res, err = openbinin(y);
775 if not res then
776 return res, err;
778 return inject_binary_input(res, nil, _name);
781 io.open_write = function(name)
782 local _name = name;
783 local res, err;
784 local y;
785 _name, y = toresourcename(name);
786 res, err = openbinout(y);
787 if not res then
788 return res, err;
790 return inject_binary_output(res, nil, _name);
793 io.mkdir = function(name)
794 local _name, y;
795 _name, y = toresourcename(name);
796 if mkdir(y) then
797 return _name;
798 else
799 return nil;
803 io.unlink = function(name)
804 local _name, y;
805 _name, y = toresourcename(name);
806 if unlink(y) then
807 return _name;
808 else
809 return nil;
813 io.rename = function(name1, name2)
814 local _name, y;
815 local _name2, y2;
816 _name, y = toresourcename(name1);
817 _name2, y2 = toresourcename(name2);
818 if rename(y, y2) then
819 return _name, _name2;
820 else
821 return nil;
825 io.transform = {};
827 io.transform.text = function()
828 return function(obj)
829 return obj:text();
833 io.transform.four_to_five = function()
834 return function(obj)
835 return obj:four_to_five();
839 io.transform.inflate = function()
840 return function(obj)
841 return obj:inflate();
845 io.transform.deflate = function()
846 return function(obj)
847 return obj:deflate();
851 io.dotransform = function(obj, ...)
852 local todo = {...};
853 local k, v;
854 local obj2, err;
855 for k, v in ipairs(todo) do
856 obj2, err = v(obj);
857 if not obj2 then
858 obj:close();
859 return nil, err;
861 obj = obj2;
863 return obj;
866 io.dotransform2 = function(obj, err, ...)
867 if not obj then
868 return obj, err;
870 return io.dotransform(obj, err, ...);
875 jpcrr.next_frame = function(name)
876 while true do
877 if not jpcrr.pc_connected() then
878 jpcrr.wait_pc_attach();
880 if jpcrr.in_frame_hold() then
881 jpcrr.release_vga();
883 if jpcrr.wait_vga() then
884 return;
890 -- Various stuff built on top of ECI.
891 local invoke = jpcrr.invoke;
892 local invokecall = jpcrr.call;
893 local invokesync = jpcrr.invoke_synchronous;
895 jpcrr.sendevent = function(...)
896 local arguments = {...};
897 local k, v;
898 for k, v in ipairs(arguments) do
899 arguments[k] = toString(v);
901 invokesync("sendevent", arguments);
904 jpcrr.save_state = function(name)
905 local _name, _fname;
906 _name, _fname = toresourcename(name);
907 invokesync("state-save", {_fname});
908 return _name;
911 jpcrr.save_movie = function(name)
912 local _name, _fname;
913 _name, _fname = toresourcename(name);
914 invokesync("movie-save", {_name});
915 return _name;
918 jpcrr.load_state_normal = function(name)
919 local _name, _fname;
920 _name, _fname = toresourcename(name);
921 invokesync("state-load", {_name});
922 return _name;
925 jpcrr.load_state_preserve_events = function(name)
926 local _name, _fname;
927 _name, _fname = toresourcename(name);
928 invokesync("state-load-noevents", {_name});
929 return _name;
932 jpcrr.load_state_movie = function(name)
933 local _name, _fname;
934 _name, _fname = toresourcename(name);
935 invokesync("state-load-movie", {_name});
936 return _name;
939 jpcrr.assemble = function()
940 invokesync("pc-assemble");
943 jpcrr.change_authors = function()
944 invokesync("change-authors");
947 jpcrr.ram_dump = function(name, binary)
948 local _name, _fname;
949 _name, _fname = toresourcename(name);
950 if binary then
951 invokesync("ram-dump-binary", {_name});
952 else
953 invokesync("ram-dump-text", {_name});
955 return _name;
958 jpcrr.hud.left_gap = function(f, g)
959 invoke("hud-left-gap", {toString(f), toString(g)});
962 jpcrr.hud.right_gap = function(f, g)
963 invoke("hud-right-gap", {toString(f), toString(g)});
966 jpcrr.hud.top_gap = function(f, g)
967 invoke("hud-top-gap", {toString(f), toString(g)});
970 jpcrr.hud.bottom_gap = function(f, g)
971 invoke("hud-bottom-gap", {toString(f), toString(g)});
974 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
975 invoke("hud-white-solid-box", {toString(f), toString(x), toString(y), toString(w), toString(h)});
978 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
979 invoke("hud-box", {toString(f), toString(x), toString(y), toString(w), toString(h),
980 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
981 toString(fg), tostring(fb), toString(fa)});
984 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
985 invoke("hud-circle", {toString(f), toString(x), toString(y), toString(r),
986 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
987 toString(fg), tostring(fb), toString(fa)});
990 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
991 invoke("hud-bitmap", {toString(f), toString(x), toString(y), bmap, toString(lr),
992 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
993 toString(fa)});
996 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
997 invoke("hud-bitmap-binary", {toString(f), toString(x), toString(y), bmap, toString(lr),
998 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
999 toString(fa)});
1002 jpcrr.set_pccontrol_pos = function(x, y)
1003 invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
1006 jpcrr.set_luaplugin_pos = function(x, y)
1007 invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
1010 jpcrr.set_pcmonitor_pos = function(x, y)
1011 invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
1014 jpcrr.set_pcstartstoptest_pos = function(x, y)
1015 invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
1018 jpcrr.set_virtualkeyboard_pos = function(x, y)
1019 invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
1022 jpcrr.exit = function()
1023 invokesync("luaplugin-terminate");
1026 jpcrr.pc_start = function()
1027 invoke("pc-start");
1030 jpcrr.pc_stop = function()
1031 invokesync("pc-stop");
1034 jpcrr.screenshot = function(include_hud)
1035 if include_hud then
1036 invoke("screenshot-renderbuffer");
1037 else
1038 invoke("screenshot-vgabuffer");
1043 jpcrr.vretrace_start_trap = function(is_on)
1044 if is_on then
1045 invokesync("trap-vretrace-start-on");
1046 else
1047 invokesync("trap-vretrace-start-off");
1051 jpcrr.vretrace_end_trap = function(is_on)
1052 if is_on then
1053 invokesync("trap-vretrace-end-on");
1054 else
1055 invokesync("trap-vretrace-end-off");
1059 jpcrr.timed_trap = function(nsecs)
1060 if nsecs then
1061 invokesync("trap-timed", {toString(nsecs)});
1062 else
1063 invokesync("trap-timed-disable");
1067 jpcrr.write_byte = function(addr, value)
1068 invokesync("memory-write", {toString(addr), toString(value), "1"});
1071 jpcrr.write_word = function(addr, value)
1072 invokesync("memory-write", {toString(addr), toString(value), "2"});
1075 jpcrr.write_dword = function(addr, value)
1076 invokesync("memory-write", {toString(addr), toString(value), "4"});
1079 jpcrr.read_byte = function(addr)
1080 local t = {toString(addr), "1"};
1081 t = invokecall("memory-read", t);
1082 return (t or {})[1];
1085 jpcrr.read_word = function(addr)
1086 local t = {toString(addr), "2"};
1087 t = invokecall("memory-read", t);
1088 return (t or {})[1];
1091 jpcrr.read_dword = function(addr)
1092 local t = {toString(addr), "4"};
1093 t = invokecall("memory-read", t);
1094 return (t or {})[1];
1097 jpcrr.invoke = nil;
1098 jpcrr.invoke_synchronous = nil;
1099 jpcrr.call = null
1101 -- Dofile.
1102 dofile = function(_script)
1103 local chunk, err, indication
1104 chunk, err = loadfile(_script);
1105 if not chunk then
1106 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1108 return chunk();
1111 local args2 = args;
1112 args = null;
1113 args = {};
1114 for k, v in pairs(args2) do
1115 if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1116 args[string.sub(k, 3)] = v;
1119 jpcrr_raw = null;
1122 chunk = null;
1123 loaded, err = pcall(function()
1124 chunk, err = loadfile(script);
1125 if not chunk then
1126 error(err);
1128 end);
1129 if not loaded then
1130 print("Kernel: Can't load script " .. script .. ": " .. err);
1131 invoke("luaplugin-terminate");
1132 while true do end
1135 script = null;
1136 indication, err = pcall(chunk);
1137 if not indication then
1138 print("Kernel: Unprotected error in script: " .. err);
1139 invoke("luaplugin-terminate");
1140 while true do end