Fix deadlock in quicksave/quickload
[jpcrr.git] / luakernel.lua
blob76f86c0c31141e7c816a1efe2c14bbdd33328ed3
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.component_encode(table components)
120 -- Return component encoding for specified components.
121 -- - jpcrr.component_decode(string line)
122 -- Return component decoding for specified line, nil/nil if it doesn't encode
123 -- anything, nil/string if parse error occurs (the error is the second return).
124 -- - jpcrr.save_state(string name)
125 -- Savestate into specified file. Returns name used.
126 -- - jpcrr.save_movie(string name)
127 -- Save movie into specified file. Returns name used.
128 -- - jpcrr.load_state_normal(string name)
129 -- Load specified savestate. Returns name used.
130 -- - jpcrr.load_state_preserve_events(string name)
131 -- Load specified savestate, preserving events. Returns name used.
132 -- - jpcrr.load_state_movie(string name)
133 -- Load specified savestate as movie. Returns name used.
134 -- - jpcrr.assemble()
135 -- Open system settings dialog.
136 -- - jpcrr.change_authors()
137 -- Open change authors dialog.
138 -- - jpcrr.exit = function()
139 -- Exit the Lua VM.
140 -- - jpcrr.ram_dump(string name, boolean binary)
141 -- Dump PC memory to specified file. If binary is true, dump is binary, otherwise
142 -- textual hexadecimal dump.
143 -- - jpcrr.write_byte(number addr, number value)
144 -- Write byte to specified physical address.
145 -- - jpcrr.write_word(number addr, number value)
146 -- Write word to specified physical address (little endian).
147 -- - jpcrr.write_dword(number addr, number value)
148 -- Write dword to specified physical address (little endian).
149 -- - jpcrr.read_byte(number addr)
150 -- Return byte from specified physical address.
151 -- - jpcrr.read_word(number addr)
152 -- Return word from specified physical address (little endian).
153 -- - jpcrr.read_dword(number addr)
154 -- Return dword from specified physical address (little endian).
155 -- - jpcrr.timed_trap(number nsecs)
156 -- Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
157 -- - jpcrr.vretrace_start_trap(boolean is_on)
158 -- Set trap on vretrace start on/off.
159 -- - jpcrr.vretrace_end_trap(boolean is_on)
160 -- Set trap on vretrace end on/off.
161 -- - jpcrr.pc_start()
162 -- Start PC execution.
163 -- - jpcrr.pc_stop()
164 -- Stop PC execution.
165 -- - jpcrr.set_pccontrol_pos(number x, number y)
166 -- Set position of PCControl window.
167 -- - jpcrr.set_luaplugin_pos(number x, number y)
168 -- Set position of LuaPlugin window.
169 -- - jpcrr.set_pcmonitor_pos(number x, number y)
170 -- Set position of PCMonitor window.
171 -- - jpcrr.set_pcstartstoptest_pos(number x, number y)
172 -- Set position of PCStartStopTest window.
173 -- - jpcrr.set_virtualkeyboard_pos(number x, number y)
174 -- Set position of VirtualKeyboard window.
175 -- - jpcrr.stringlessthan(String x, String y)
176 -- Return true if x is before y in codepoint lexical order, otherwise false.
177 -- - jpcrr.screenshot(boolean include_hud)
178 -- Take screen shot (Requires monitor). If include_hud is true, include HUD
179 -- (as shown on screen). Note that this should only be called during frame
180 -- hold or results are pretty much undefined.
181 -- - jpcrr.sendevent(string/number...)
182 -- Sends specified event.
184 -- I/O functions have the following conventions. If function returns any real data, the first
185 -- return value returns this data or is nil. Otherwise first return value is true or false.
186 -- If first return value is nil or false, then the second return value gives textual error
187 -- message for failed operation, or is nil if EOF occured before anything was read.
189 -- Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
190 -- success or failure.
192 -- Specifying nil as name of file results random filename being used (it even works with unlink,
193 -- mkdir, rename and read-only access, but doesn't make any sense there).
195 -- Class: BinaryFile:
196 -- Binary file for RO or RW access. Methods are as follows:
197 -- - name()
198 -- Return name of file.
199 -- - length()
200 -- Return length of file.
201 -- - set_length(number length)
202 -- Truncate file to specified length
203 -- - read(number offset, number length)
204 -- Read up to length bytes from offset.
205 -- - write(number offset, string content)
206 -- Write content to specified offset.
207 -- - close()
208 -- Close the file.
209 -- Class: BinaryInput:
210 -- Binary file for sequential input. Methods are as follows:
211 -- - name()
212 -- Return name of file.
213 -- - four_to_five()
214 -- Return BinaryInput that is four to five decoding of this stream.
215 -- - text()
216 -- Return stream as TextInput.
217 -- - inflate()
218 -- Return BinaryInput that is inflate of this stream.
219 -- - read(number bytes)
220 -- Read up to bytes bytes from file.
221 -- - read()
222 -- Read the entiere file at once.
223 -- - close()
224 -- Close the file.
225 -- Character set for binary files is Latin-1.
227 -- Class: BinaryOutput:
228 -- Binary file for sequential output. Methods are as follows:
229 -- - name()
230 -- Return name of file.
231 -- - four_to_five()
232 -- Return BinaryOutput that writes four to five encoded output to this stream.
233 -- - text()
234 -- Return stream as TextOutput.
235 -- - deflate()
236 -- Return BinaryOutput that writes deflate output to this stream.
237 -- - write(string content)
238 -- Write string to file.
239 -- - close()
240 -- Close the file.
241 -- Character set for binary files is Latin-1.
243 -- Class: TextInput:
244 -- - name()
245 -- Return name of file.
246 -- - read()
247 -- Read line from file.
248 -- - read_component()
249 -- Read next componented line into array.
250 -- - lines()
251 -- Line iterator function.
252 -- - close()
253 -- Close the file.
254 -- Character set for text files is UTF-8.
256 -- Class: TextOutput:
257 -- - name()
258 -- Return name of file.
259 -- - write(string line)
260 -- Write line line to file.
261 -- - write_component(table components)
262 -- Write componented line.
263 -- - close()
264 -- Close the file.
265 -- Character set for text files is UTF-8.
267 -- Class ArchiveIn:
268 -- - member(string name)
269 -- Open substream for member name. The methods are the same as for io.opentextin.
270 -- - member_binary(string name)
271 -- Open binary (four to five) substream for member name. The methods are the same as
272 -- for io.openbinaryin.
273 -- - close()
274 -- Close the file. Any opened substreams are invalidated.
275 -- - member_list()
276 -- Return table listing all members of archive (sorted by name).
277 -- Class ArchiveOut:
278 -- - member(string name)
279 -- Open substream for member name. The methods are the same as for io.opentextout. Note that
280 -- previous member must be closed before next can open.
281 -- - member_binary(string name)
282 -- Open binary (four to five) substream for member name. The methods are the same as
283 -- for io.openbinaryout. Note that previous substream must be closed before next can open.
284 -- - commit()
285 -- Commit the file. No substream may be open. Closes the file.
286 -- - rollback()
287 -- Rollback the file. No substream may be open. Closes the file.
289 -- - io.open(string name, string mode) -> BinaryFile
290 -- Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
291 -- write).
292 -- - io.open_read(string name) -> BinaryInput
293 -- Open file named @name as binary input stream.
294 -- - io.open_write(string name) -> BinaryOutput
295 -- Open file named @name as binary input stream.
296 -- - io.open_arch_read(string name) -> ArchiveIn
297 -- Open file named @name as input archive.
298 -- - io.open_arch_write(string name) -> ArchiveOut
299 -- Open file named @name as output archive.
300 -- - io.mkdir(string name)
301 -- Create directory name. Returns name created on success, nil on failure.
302 -- - io.unlink(string name)
303 -- Delete file/directory name. Returns name deleted on success, nil on failure.
304 -- - io.rename(string old, string new)
305 -- Rename file old -> new. Returns old, new on success, nil on failure.
306 -- - io.transform.text()
307 -- Returns function that calls text() method of its parameter.
308 -- - io.transform.four_to_five()
309 -- Returns function that calls four_to_five() method of its parameter.
310 -- - io.transform.deflate()
311 -- Returns function that calls deflate() method of its parameter.
312 -- - io.transform.inflate()
313 -- Returns function that calls inflate() method of its parameter.
314 -- - io.dotransform(object obj, function...)
315 -- Call specified functions on specified object. If any function fails (first argument nil
316 -- or false), call close method on preceeding object. Otherwise call specified functions
317 -- chained left to right and return the result.
318 -- - io.dotransform2(object obj, string err, function...)
319 -- Similar to dotransform except if obj is nil or false, returns obj, err.
325 local handle, err, chunk, indication, k, v;
327 local loadmod = loadmodule;
328 loadmodule = nil;
330 local export_module_in = function(tab, modname, prefix)
331 local fun = loadmod(modname);
332 for k, v in pairs(fun) do
333 tab[(prefix or "") .. k] = v;
337 jpcrr = {};
338 jpcrr.hud = {};
339 bit = {};
340 io = {};
342 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
343 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
344 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
345 export_module_in(bit, "org.jpc.luaextensions.Bitops");
347 -- Few misc functions.
348 assert = function(val, err)
349 if (not val) and err then
350 error(err);
352 return val;
355 modulus_split = function(number, ...)
356 local dividers = {...};
357 local results = {};
358 local rem;
360 for k, v in ipairs(dividers) do
361 rem = number % v;
362 table.insert(results, (number - rem) / v);
363 number = rem;
366 table.insert(results, number);
367 return unpack(results);
370 local getmtable = getmetatable;
371 local toString = tostring;
372 local inject_binary_file;
373 local inject_binary_input;
374 local inject_binary_output;
375 local inject_text_input;
376 local inject_text_output;
377 local inject_archive_input;
378 local inject_archive_output;
380 -- Class member injectors.
381 inject_binary_file = function(obj, name)
382 local _name = name;
383 getmtable(obj).name = function(obj)
384 return _name;
386 getmtable(obj).__index = function(tab, name)
387 local x = getmtable(obj)[name];
388 if x then
389 return x;
391 error("Invalid method " .. name .. " for BinaryFile");
393 return obj;
396 inject_binary_input = function(obj, underlying, name)
397 local _name = name;
398 local old_four_to_five = getmtable(obj).four_to_five;
399 local old_inflate = getmtable(obj).inflate;
400 local old_text = getmtable(obj).text;
401 local old_read = getmtable(obj).read;
402 local old_close = getmtable(obj).close;
403 local underlying_object = underlying;
405 getmtable(obj).name = function(obj)
406 return _name;
408 getmtable(obj).four_to_five = function(obj)
409 local res, err;
410 res, err = old_four_to_five(obj);
411 if not res then
412 return res, err;
414 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
416 getmtable(obj).inflate = function(obj)
417 local res, err;
418 res, err = old_inflate(obj);
419 if not res then
420 return res, err;
422 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
424 getmtable(obj).text = function(obj)
425 local res, err;
426 res, err = old_text(obj);
427 if not res then
428 return res, err;
430 return inject_text_input(res, obj, "text<" .. _name .. ">");
432 getmtable(obj).read = function(obj, toread)
433 if toread then
434 return old_read(obj, toread);
435 else
436 local res = "";
437 local ret, err;
438 while true do
439 ret, err = old_read(obj, 16384);
440 if not ret then
441 if not err then
442 return res;
444 return nil, err;
446 res = res .. ret;
450 getmtable(obj).close = function(obj)
451 local ret, err, ret2, err2;
452 ret, err = old_close(obj);
453 if underlying_object then ret2, err2 = underlying_object:close(); end
454 if ret and not ret2 then
455 err = err2;
456 ret = ret2;
458 return ret, err;
460 getmtable(obj).__index = function(tab, name)
461 local x = getmtable(obj)[name];
462 if x then
463 return x;
465 error("Invalid method " .. name .. " for BinaryInput");
467 return obj;
470 inject_binary_output = function(obj, underlying, name)
471 local _name = name;
472 local old_four_to_five = getmtable(obj).four_to_five;
473 local old_deflate = getmtable(obj).deflate;
474 local old_text = getmtable(obj).text;
475 local old_close = getmtable(obj).close;
476 local underlying_object = underlying;
478 getmtable(obj).name = function(obj)
479 return _name;
481 getmtable(obj).four_to_five = function(obj)
482 local res, err;
483 res, err = old_four_to_five(obj);
484 if not res then
485 return res, err;
487 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
489 getmtable(obj).deflate = function(obj)
490 local res, err;
491 res, err = old_deflate(obj);
492 if not res then
493 return res, err;
495 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
497 getmtable(obj).text = function(obj)
498 local res, err;
499 res, err = old_text(obj);
500 if not res then
501 return res, err;
503 return inject_text_output(res, obj, "text<" .. _name .. ">");
505 getmtable(obj).close = function(obj)
506 local ret, err, ret2, err2;
507 ret, err = old_close(obj);
508 if underlying_object then ret2, err2 = underlying_object:close(); end
509 if ret and not ret2 then
510 err = err2;
511 ret = ret2;
513 return ret, err;
515 getmtable(obj).__index = function(tab, name)
516 local x = getmtable(obj)[name];
517 if x then
518 return x;
520 error("Invalid method " .. name .. " for BinaryOutput");
522 return obj;
525 inject_text_input = function(obj, underlying, name)
526 local _name = name;
527 local old_close = getmtable(obj).close;
528 local underlying_object = underlying;
530 getmtable(obj).lines = function(obj)
531 return function(state, prevline)
532 return state:read();
533 end, obj, nil;
535 getmtable(obj).name = function(obj)
536 return _name;
538 getmtable(obj).close = function(obj)
539 local ret, err, ret2, err2;
540 ret, err = old_close(obj);
541 if underlying_object then ret2, err2 = underlying_object:close(); end
542 if ret and not ret2 then
543 err = err2;
544 ret = ret2;
546 return ret, err;
548 getmtable(obj).__index = function(tab, name)
549 local x = getmtable(obj)[name];
550 if x then
551 return x;
553 error("Invalid method " .. name .. " for TextInput");
555 return obj;
558 inject_text_output = function(obj, underlying, name)
559 local _name = name;
560 local old_close = getmtable(obj).close;
561 local underlying_object = underlying;
563 getmtable(obj).name = function(obj)
564 return _name;
566 getmtable(obj).close = function(obj)
567 local ret, err, ret2, err2;
568 ret, err = old_close(obj);
569 if underlying_object then ret2, err2 = underlying_object:close(); end
570 if ret and underlying_object then
571 err = err2;
572 ret = ret2;
574 return ret, err;
576 getmtable(obj).__index = function(tab, name)
577 local x = getmtable(obj)[name];
578 if x then
579 return x;
581 error("Invalid method " .. name .. " for TextOutput");
583 return obj;
586 inject_archive_input = function(obj, name)
587 local _name = name;
588 local old_member = getmtable(obj).member;
589 local old_member_list = getmtable(obj).member_list;
590 getmtable(obj).member = function(obj, member)
591 local res, err;
592 res, err = old_member(obj, member);
593 if not res then
594 return res, err;
596 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
598 getmtable(obj).name = function(obj)
599 return _name;
601 getmtable(obj).member_list = function(obj)
602 local tab = old_member_list(obj);
603 if tab then table.sort(tab, jpcrr.stringlessthan); end
604 return tab;
606 getmtable(obj).__index = function(tab, name)
607 local x = getmtable(obj)[name];
608 if x then
609 return x;
611 error("Invalid method " .. name .. " for ArchiveInput");
613 return obj;
616 inject_archive_output = function(obj, name)
617 local _name = name;
618 local old_member = getmtable(obj).member;
619 getmtable(obj).member = function(obj, member)
620 local res, err;
621 res, err = old_member(obj, member);
622 if not res then
623 return res, err;
625 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
627 getmtable(obj).name = function(obj)
628 return _name;
630 getmtable(obj).__index = function(tab, name)
631 local x = getmtable(obj)[name];
632 if x then
633 return x;
635 error("Invalid method " .. name .. " for ArchiveOutput");
637 return obj;
641 -- Redefined print.
643 local rprint = print_console_msg;
644 print_console_msg = nil;
645 print = function(...)
646 local x = "";
647 local y = {...};
648 local i;
649 for i = 1,#y do
650 if i > 1 then
651 x = x .. "\t" .. toString(y[i]);
652 else
653 x = toString(y[i]);
656 rprint(x);
658 print_console_msg = nil;
661 -- I/O routines.
662 local stringfind = string.find;
663 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
664 local path = args["luapath"] or ".";
665 local toresourcename = function(resname)
666 if not resname then
667 return randname(path .. "/", "luatemp-");
670 if not stringfind(resname, "[%d%l%u_%-]") then
671 error("Bad resource name (case 1): " .. resname);
673 if stringfind(resname, "^/") then
674 error("Bad resource name (case 2): " .. resname);
676 if stringfind(resname, "%.%.") then
677 error("Bad resource name (case 3): " .. resname);
679 if stringfind(resname, "\\") then
680 error("Bad resource name (case 4): " .. resname);
683 return resname, path .. "/" .. resname;
688 local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
689 local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
690 local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
691 local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
692 local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
694 local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
695 local mkdir = baseFS.mkdir;
696 local unlink = baseFS.unlink;
697 local rename = baseFS.rename;
699 local getmtable = getmetatable;
701 loadfile = function(_script)
702 local file, file2, err, content;
703 local x, y;
704 x, y = toresourcename(_script);
705 file, err = openbinin(y, "r");
706 if not file then
707 return nil, "Can't open " .. _script .. ": " .. err;
709 file2, err = file:text();
710 if not file2 then
711 return nil, "Can't transform " .. _script .. ": " .. err;
713 content = "";
714 line = file2:read();
715 while line do
716 content = content .. line .. "\n";
717 line = file2:read();
719 file2:close();
720 file:close();
721 return loadstring(content, _script);
724 io.open = function(name, mode)
725 local _name;
726 local res, err;
727 local y;
728 _name, y = toresourcename(name);
729 res, err = openbinary(y, mode);
730 if not res then
731 return res, err;
733 return inject_binary_file(res, _name);
736 io.open_arch_read = function(name)
737 local _name = name;
738 local res, err;
739 local y;
740 _name, y = toresourcename(name);
741 res, err = openarchin(y);
742 if not res then
743 return res, err;
745 return inject_archive_input(res, _name);
748 io.open_arch_write = function(name)
749 local _name = name;
750 local res, err;
751 local y;
752 _name, y = toresourcename(name);
753 res, err = openarchout(y);
754 if not res then
755 return res, err;
757 return inject_archive_output(res, _name);
760 io.open_read = function(name)
761 local _name = name;
762 local res, err;
763 local y;
764 _name, y = toresourcename(name);
765 res, err = openbinin(y);
766 if not res then
767 return res, err;
769 return inject_binary_input(res, nil, _name);
772 io.open_write = function(name)
773 local _name = name;
774 local res, err;
775 local y;
776 _name, y = toresourcename(name);
777 res, err = openbinout(y);
778 if not res then
779 return res, err;
781 return inject_binary_output(res, nil, _name);
784 io.mkdir = function(name)
785 local _name, y;
786 _name, y = toresourcename(name);
787 if mkdir(y) then
788 return _name;
789 else
790 return nil;
794 io.unlink = function(name)
795 local _name, y;
796 _name, y = toresourcename(name);
797 if unlink(y) then
798 return _name;
799 else
800 return nil;
804 io.rename = function(name1, name2)
805 local _name, y;
806 local _name2, y2;
807 _name, y = toresourcename(name1);
808 _name2, y2 = toresourcename(name2);
809 if rename(y, y2) then
810 return _name, _name2;
811 else
812 return nil;
816 io.transform = {};
818 io.transform.text = function()
819 return function(obj)
820 return obj:text();
824 io.transform.four_to_five = function()
825 return function(obj)
826 return obj:four_to_five();
830 io.transform.inflate = function()
831 return function(obj)
832 return obj:inflate();
836 io.transform.deflate = function()
837 return function(obj)
838 return obj:deflate();
842 io.dotransform = function(obj, ...)
843 local todo = {...};
844 local k, v;
845 local obj2, err;
846 for k, v in ipairs(todo) do
847 obj2, err = v(obj);
848 if not obj2 then
849 obj:close();
850 return nil, err;
852 obj = obj2;
854 return obj;
857 io.dotransform2 = function(obj, err, ...)
858 if not obj then
859 return obj, err;
861 return io.dotransform(obj, err, ...);
866 jpcrr.next_frame = function(name)
867 while true do
868 if not jpcrr.pc_connected() then
869 jpcrr.wait_pc_attach();
871 if jpcrr.in_frame_hold() then
872 jpcrr.release_vga();
874 if jpcrr.wait_vga() then
875 return;
881 -- Various stuff built on top of ECI.
882 local invoke = jpcrr.invoke;
883 local invokecall = jpcrr.call;
884 local invokesync = jpcrr.invoke_synchronous;
886 jpcrr.sendevent = function(...)
887 local arguments = {...};
888 local k, v;
889 for k, v in ipairs(arguments) do
890 arguments[k] = toString(v);
892 invokesync("sendevent", arguments);
895 jpcrr.save_state = function(name)
896 local _name, _fname;
897 _name, _fname = toresourcename(name);
898 invokesync("state-save", {_fname});
899 return _name;
902 jpcrr.save_movie = function(name)
903 local _name, _fname;
904 _name, _fname = toresourcename(name);
905 invokesync("movie-save", {_name});
906 return _name;
909 jpcrr.load_state_normal = function(name)
910 local _name, _fname;
911 _name, _fname = toresourcename(name);
912 invokesync("state-load", {_name});
913 return _name;
916 jpcrr.load_state_preserve_events = function(name)
917 local _name, _fname;
918 _name, _fname = toresourcename(name);
919 invokesync("state-load-noevents", {_name});
920 return _name;
923 jpcrr.load_state_movie = function(name)
924 local _name, _fname;
925 _name, _fname = toresourcename(name);
926 invokesync("state-load-movie", {_name});
927 return _name;
930 jpcrr.assemble = function()
931 invokesync("pc-assemble");
934 jpcrr.change_authors = function()
935 invokesync("change-authors");
938 jpcrr.ram_dump = function(name, binary)
939 local _name, _fname;
940 _name, _fname = toresourcename(name);
941 if binary then
942 invokesync("ram-dump-binary", {_name});
943 else
944 invokesync("ram-dump-text", {_name});
946 return _name;
949 jpcrr.hud.left_gap = function(f, g)
950 invoke("hud-left-gap", {toString(f), toString(g)});
953 jpcrr.hud.right_gap = function(f, g)
954 invoke("hud-right-gap", {toString(f), toString(g)});
957 jpcrr.hud.top_gap = function(f, g)
958 invoke("hud-top-gap", {toString(f), toString(g)});
961 jpcrr.hud.bottom_gap = function(f, g)
962 invoke("hud-bottom-gap", {toString(f), toString(g)});
965 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
966 invoke("hud-white-solid-box", {toString(f), toString(x), toString(y), toString(w), toString(h)});
969 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
970 invoke("hud-box", {toString(f), toString(x), toString(y), toString(w), toString(h),
971 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
972 toString(fg), tostring(fb), toString(fa)});
975 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
976 invoke("hud-circle", {toString(f), toString(x), toString(y), toString(r),
977 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
978 toString(fg), tostring(fb), toString(fa)});
981 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
982 invoke("hud-bitmap", {toString(f), toString(x), toString(y), bmap, toString(lr),
983 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
984 toString(fa)});
987 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
988 invoke("hud-bitmap-binary", {toString(f), toString(x), toString(y), bmap, toString(lr),
989 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
990 toString(fa)});
993 jpcrr.set_pccontrol_pos = function(x, y)
994 invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
997 jpcrr.set_luaplugin_pos = function(x, y)
998 invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
1001 jpcrr.set_pcmonitor_pos = function(x, y)
1002 invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
1005 jpcrr.set_pcstartstoptest_pos = function(x, y)
1006 invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
1009 jpcrr.set_virtualkeyboard_pos = function(x, y)
1010 invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
1013 jpcrr.exit = function()
1014 invokesync("luaplugin-terminate");
1017 jpcrr.pc_start = function()
1018 invoke("pc-start");
1021 jpcrr.pc_stop = function()
1022 invokesync("pc-stop");
1025 jpcrr.screenshot = function(include_hud)
1026 if include_hud then
1027 invoke("screenshot-renderbuffer");
1028 else
1029 invoke("screenshot-vgabuffer");
1034 jpcrr.vretrace_start_trap = function(is_on)
1035 if is_on then
1036 invokesync("trap-vretrace-start-on");
1037 else
1038 invokesync("trap-vretrace-start-off");
1042 jpcrr.vretrace_end_trap = function(is_on)
1043 if is_on then
1044 invokesync("trap-vretrace-end-on");
1045 else
1046 invokesync("trap-vretrace-end-off");
1050 jpcrr.timed_trap = function(nsecs)
1051 if nsecs then
1052 invokesync("trap-timed", {toString(nsecs)});
1053 else
1054 invokesync("trap-timed-disable");
1058 jpcrr.write_byte = function(addr, value)
1059 invokesync("memory-write", {toString(addr), toString(value), "1"});
1062 jpcrr.write_word = function(addr, value)
1063 invokesync("memory-write", {toString(addr), toString(value), "2"});
1066 jpcrr.write_dword = function(addr, value)
1067 invokesync("memory-write", {toString(addr), toString(value), "4"});
1070 jpcrr.read_byte = function(addr)
1071 local t = {toString(addr), "1"};
1072 t = invokecall("memory-read", t);
1073 return (t or {})[1];
1076 jpcrr.read_word = function(addr)
1077 local t = {toString(addr), "2"};
1078 t = invokecall("memory-read", t);
1079 return (t or {})[1];
1082 jpcrr.read_dword = function(addr)
1083 local t = {toString(addr), "4"};
1084 t = invokecall("memory-read", t);
1085 return (t or {})[1];
1088 jpcrr.invoke = nil;
1089 jpcrr.invoke_synchronous = nil;
1090 jpcrr.call = null
1092 -- Dofile.
1093 dofile = function(_script)
1094 local chunk, err, indication
1095 chunk, err = loadfile(_script);
1096 if not chunk then
1097 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1099 return chunk();
1102 local args2 = args;
1103 args = null;
1104 args = {};
1105 for k, v in pairs(args2) do
1106 if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1107 args[string.sub(k, 3)] = v;
1110 jpcrr_raw = null;
1113 chunk = null;
1114 loaded, err = pcall(function()
1115 chunk, err = loadfile(script);
1116 if not chunk then
1117 error(err);
1119 end);
1120 if not loaded then
1121 print("Kernel: Can't load script " .. script .. ": " .. err);
1122 invoke("luaplugin-terminate");
1123 while true do end
1126 script = null;
1127 indication, err = pcall(chunk);
1128 if not indication then
1129 print("Kernel: Unprotected error in script: " .. err);
1130 invoke("luaplugin-terminate");
1131 while true do end