Fix ECI with varargs
[jpcrr.git] / luakernel.lua
blob0bf8c6c2cd5631a344575b9b0744ac6be00a87d2
1 --
2 -- Copyright 2009 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.pc_running()
58 -- Returns true if PC is running.
59 -- - jpcrr.clock_time()
60 -- Returns current time or nil if no PC.
61 -- - jpcrr.pc_connected()
62 -- Returns true if PC is connected.
63 -- - jpcrr.wait_pc_attach()
64 -- Wait for PC to attach.
65 -- - jpcrr.next_frame()
66 -- Wait for next frame output hold.
67 -- - jpcrr.in_frame_hold()
68 -- Returns true if in frame hold, false otherwise.
69 -- - jpcrr.keypressed(number key)
70 -- Return true if key is pressed, else false.
71 -- - jpcrr.wait_vga()
72 -- Waits for VGA to enter frame hold mode. Frame hold happens once per frame.
73 -- - jpcrr.release_vga()
74 -- Allow VGA to exit frame hold mode. Wait for frame hold first.
75 -- - jpcrr.vga_resolution()
76 -- Return VGA x and y resolutions. -1x-1 or 0x0 is returned if no valid resolution.
77 -- Should only be called during frame hold.
78 -- - jpcrr.hud.left_gap(number flags, number gap)
79 -- Set left gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
80 -- 1 (2) is set, dump to video dump.
81 -- - jpcrr.hud.right_gap(number flags, number gap)
82 -- Set right gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
83 -- 1 (2) is set, dump to video dump.
84 -- - jpcrr.hud.top_gap(number flags, number gap)
85 -- Set top gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
86 -- 1 (2) is set, dump to video dump.
87 -- - jpcrr.hud.bottom_gap(number flags, number gap)
88 -- Set bottom gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
89 -- 1 (2) is set, dump to video dump.
90 -- - jpcrr.hud.white_solid_box(number flags, number x, number y, number w, number h)
91 -- Draw with solid opaque box.
92 -- - jpcrr.hud.box(number flags, number x, number y, number w, number h, number linethick,
93 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
94 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
95 -- Draw box with specified size, border line thickness, line color and fill color.
96 -- - jpcrr.hud.circle(number flags, number x, number y, number r, number linethick,
97 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
98 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
99 -- Draw circle with specified size, border line thickness, line color and fill color.
100 -- - jpcrr.hud.bitmap(number flags, number x, number y, string bmap,
101 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
102 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
103 -- Draw bitmap with specified foreground color and background color.
104 -- - jpcrr.hud.bitmap_binary(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 binary bitmap with specified foreground color and background color.
108 -- - jpcrr.joystick_state()
109 -- Returns nil if no joystick. Otherwise returns hold times for all four axis (numeric)
110 -- followed by button states (boolean).
111 -- - jpcrr.component_encode(table components)
112 -- Return component encoding for specified components.
113 -- - jpcrr.component_decode(string line)
114 -- Return component decoding for specified line, nil/nil if it doesn't encode
115 -- anything, nil/string if parse error occurs (the error is the second return).
116 -- - jpcrr.save_state(string name)
117 -- Savestate into specified file. Returns name used.
118 -- - jpcrr.save_movie(string name)
119 -- Save movie into specified file. Returns name used.
120 -- - jpcrr.load_state_normal(string name)
121 -- Load specified savestate. Returns name used.
122 -- - jpcrr.load_state_preserve_events(string name)
123 -- Load specified savestate, preserving events. Returns name used.
124 -- - jpcrr.load_state_movie(string name)
125 -- Load specified savestate as movie. Returns name used.
126 -- - jpcrr.assemble()
127 -- Open system settings dialog.
128 -- - jpcrr.change_authors()
129 -- Open change authors dialog.
130 -- - jpcrr.exit = function()
131 -- Exit the Lua VM.
132 -- - jpcrr.ram_dump(string name, boolean binary)
133 -- Dump PC memory to specified file. If binary is true, dump is binary, otherwise
134 -- textual hexadecimal dump.
135 -- - jpcrr.write_byte(number addr, number value)
136 -- Write byte to specified physical address.
137 -- - jpcrr.write_word(number addr, number value)
138 -- Write word to specified physical address (little endian).
139 -- - jpcrr.write_dword(number addr, number value)
140 -- Write dword to specified physical address (little endian).
141 -- - jpcrr.read_byte(number addr)
142 -- Return byte from specified physical address.
143 -- - jpcrr.read_word(number addr)
144 -- Return word from specified physical address (little endian).
145 -- - jpcrr.read_dword(number addr)
146 -- Return dword from specified physical address (little endian).
147 -- - jpcrr.timed_trap(number nsecs)
148 -- Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
149 -- - jpcrr.vretrace_start_trap(boolean is_on)
150 -- Set trap on vretrace start on/off.
151 -- - jpcrr.vretrace_end_trap(boolean is_on)
152 -- Set trap on vretrace end on/off.
153 -- - jpcrr.pc_start()
154 -- Start PC execution.
155 -- - jpcrr.pc_stop()
156 -- Stop PC execution.
157 -- - jpcrr.set_pccontrol_pos(number x, number y)
158 -- Set position of PCControl window.
159 -- - jpcrr.set_luaplugin_pos(number x, number y)
160 -- Set position of LuaPlugin window.
161 -- - jpcrr.set_pcmonitor_pos(number x, number y)
162 -- Set position of PCMonitor window.
163 -- - jpcrr.set_pcstartstoptest_pos(number x, number y)
164 -- Set position of PCStartStopTest window.
165 -- - jpcrr.set_virtualkeyboard_pos(number x, number y)
166 -- Set position of VirtualKeyboard window.
167 -- - jpcrr.stringlessthan(String x, String y)
168 -- Return true if x is before y in codepoint lexical order, otherwise false.
169 -- - jpcrr.screenshot(boolean include_hud)
170 -- Take screen shot (Requires monitor). If include_hud is true, include HUD
171 -- (as shown on screen). Note that this should only be called during frame
172 -- hold or results are pretty much undefined.
174 -- I/O functions have the following conventions. If function returns any real data, the first
175 -- return value returns this data or is nil. Otherwise first return value is true or false.
176 -- If first return value is nil or false, then the second return value gives textual error
177 -- message for failed operation, or is nil if EOF occured before anything was read.
179 -- Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
180 -- success or failure.
182 -- Specifying nil as name of file results random filename being used (it even works with unlink,
183 -- mkdir, rename and read-only access, but doesn't make any sense there).
185 -- Class: BinaryFile:
186 -- Binary file for RO or RW access. Methods are as follows:
187 -- - name()
188 -- Return name of file.
189 -- - length()
190 -- Return length of file.
191 -- - set_length(number length)
192 -- Truncate file to specified length
193 -- - read(number offset, number length)
194 -- Read up to length bytes from offset.
195 -- - write(number offset, string content)
196 -- Write content to specified offset.
197 -- - close()
198 -- Close the file.
199 -- Class: BinaryInput:
200 -- Binary file for sequential input. Methods are as follows:
201 -- - name()
202 -- Return name of file.
203 -- - four_to_five()
204 -- Return BinaryInput that is four to five decoding of this stream.
205 -- - text()
206 -- Return stream as TextInput.
207 -- - inflate()
208 -- Return BinaryInput that is inflate of this stream.
209 -- - read(number bytes)
210 -- Read up to bytes bytes from file.
211 -- - read()
212 -- Read the entiere file at once.
213 -- - close()
214 -- Close the file.
215 -- Character set for binary files is Latin-1.
217 -- Class: BinaryOutput:
218 -- Binary file for sequential output. Methods are as follows:
219 -- - name()
220 -- Return name of file.
221 -- - four_to_five()
222 -- Return BinaryOutput that writes four to five encoded output to this stream.
223 -- - text()
224 -- Return stream as TextOutput.
225 -- - deflate()
226 -- Return BinaryOutput that writes deflate output to this stream.
227 -- - write(string content)
228 -- Write string to file.
229 -- - close()
230 -- Close the file.
231 -- Character set for binary files is Latin-1.
233 -- Class: TextInput:
234 -- - name()
235 -- Return name of file.
236 -- - read()
237 -- Read line from file.
238 -- - read_component()
239 -- Read next componented line into array.
240 -- - lines()
241 -- Line iterator function.
242 -- - close()
243 -- Close the file.
244 -- Character set for text files is UTF-8.
246 -- Class: TextOutput:
247 -- - name()
248 -- Return name of file.
249 -- - write(string line)
250 -- Write line line to file.
251 -- - write_component(table components)
252 -- Write componented line.
253 -- - close()
254 -- Close the file.
255 -- Character set for text files is UTF-8.
257 -- Class ArchiveIn:
258 -- - member(string name)
259 -- Open substream for member name. The methods are the same as for io.opentextin.
260 -- - member_binary(string name)
261 -- Open binary (four to five) substream for member name. The methods are the same as
262 -- for io.openbinaryin.
263 -- - close()
264 -- Close the file. Any opened substreams are invalidated.
265 -- - member_list()
266 -- Return table listing all members of archive (sorted by name).
267 -- Class ArchiveOut:
268 -- - member(string name)
269 -- Open substream for member name. The methods are the same as for io.opentextout. Note that
270 -- previous member must be closed before next can open.
271 -- - member_binary(string name)
272 -- Open binary (four to five) substream for member name. The methods are the same as
273 -- for io.openbinaryout. Note that previous substream must be closed before next can open.
274 -- - commit()
275 -- Commit the file. No substream may be open. Closes the file.
276 -- - rollback()
277 -- Rollback the file. No substream may be open. Closes the file.
279 -- - io.open(string name, string mode) -> BinaryFile
280 -- Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
281 -- write).
282 -- - io.open_read(string name) -> BinaryInput
283 -- Open file named @name as binary input stream.
284 -- - io.open_write(string name) -> BinaryOutput
285 -- Open file named @name as binary input stream.
286 -- - io.open_arch_read(string name) -> ArchiveIn
287 -- Open file named @name as input archive.
288 -- - io.open_arch_write(string name) -> ArchiveOut
289 -- Open file named @name as output archive.
290 -- - io.mkdir(string name)
291 -- Create directory name. Returns name created on success, nil on failure.
292 -- - io.unlink(string name)
293 -- Delete file/directory name. Returns name deleted on success, nil on failure.
294 -- - io.rename(string old, string new)
295 -- Rename file old -> new. Returns old, new on success, nil on failure.
296 -- - io.transform.text()
297 -- Returns function that calls text() method of its parameter.
298 -- - io.transform.four_to_five()
299 -- Returns function that calls four_to_five() method of its parameter.
300 -- - io.transform.deflate()
301 -- Returns function that calls deflate() method of its parameter.
302 -- - io.transform.inflate()
303 -- Returns function that calls inflate() method of its parameter.
304 -- - io.dotransform(object obj, function...)
305 -- Call specified functions on specified object. If any function fails (first argument nil
306 -- or false), call close method on preceeding object. Otherwise call specified functions
307 -- chained left to right and return the result.
308 -- - io.dotransform2(object obj, string err, function...)
309 -- Similar to dotransform except if obj is nil or false, returns obj, err.
315 local handle, err, chunk, indication, k, v;
317 local loadmod = loadmodule;
318 loadmodule = nil;
320 local export_module_in = function(tab, modname, prefix)
321 local fun = loadmod(modname);
322 for k, v in pairs(fun) do
323 tab[(prefix or "") .. k] = v;
327 jpcrr = {};
328 jpcrr.hud = {};
329 bit = {};
330 io = {};
332 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
333 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
334 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
335 export_module_in(bit, "org.jpc.luaextensions.Bitops");
337 -- Few misc functions.
338 assert = function(val, err)
339 if (not val) and err then
340 error(err);
342 return val;
345 modulus_split = function(number, ...)
346 local dividers = {...};
347 local results = {};
348 local rem;
350 for k, v in ipairs(dividers) do
351 rem = number % v;
352 table.insert(results, (number - rem) / v);
353 number = rem;
356 table.insert(results, number);
357 return unpack(results);
360 local getmtable = getmetatable;
361 local toString = tostring;
362 local inject_binary_file;
363 local inject_binary_input;
364 local inject_binary_output;
365 local inject_text_input;
366 local inject_text_output;
367 local inject_archive_input;
368 local inject_archive_output;
370 -- Class member injectors.
371 inject_binary_file = function(obj, name)
372 local _name = name;
373 getmtable(obj).name = function(obj)
374 return _name;
376 getmtable(obj).__index = function(tab, name)
377 local x = getmtable(obj)[name];
378 if x then
379 return x;
381 error("Invalid method " .. name .. " for BinaryFile");
383 return obj;
386 inject_binary_input = function(obj, underlying, name)
387 local _name = name;
388 local old_four_to_five = getmtable(obj).four_to_five;
389 local old_inflate = getmtable(obj).inflate;
390 local old_text = getmtable(obj).text;
391 local old_read = getmtable(obj).read;
392 local old_close = getmtable(obj).close;
393 local underlying_object = underlying;
395 getmtable(obj).name = function(obj)
396 return _name;
398 getmtable(obj).four_to_five = function(obj)
399 local res, err;
400 res, err = old_four_to_five(obj);
401 if not res then
402 return res, err;
404 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
406 getmtable(obj).inflate = function(obj)
407 local res, err;
408 res, err = old_inflate(obj);
409 if not res then
410 return res, err;
412 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
414 getmtable(obj).text = function(obj)
415 local res, err;
416 res, err = old_text(obj);
417 if not res then
418 return res, err;
420 return inject_text_input(res, obj, "text<" .. _name .. ">");
422 getmtable(obj).read = function(obj, toread)
423 if toread then
424 return old_read(obj, toread);
425 else
426 local res = "";
427 local ret, err;
428 while true do
429 ret, err = old_read(obj, 16384);
430 if not ret then
431 if not err then
432 return res;
434 return nil, err;
436 res = res .. ret;
440 getmtable(obj).close = function(obj)
441 local ret, err, ret2, err2;
442 ret, err = old_close(obj);
443 if underlying_object then ret2, err2 = underlying_object:close(); end
444 if ret and not ret2 then
445 err = err2;
446 ret = ret2;
448 return ret, err;
450 getmtable(obj).__index = function(tab, name)
451 local x = getmtable(obj)[name];
452 if x then
453 return x;
455 error("Invalid method " .. name .. " for BinaryInput");
457 return obj;
460 inject_binary_output = function(obj, underlying, name)
461 local _name = name;
462 local old_four_to_five = getmtable(obj).four_to_five;
463 local old_deflate = getmtable(obj).deflate;
464 local old_text = getmtable(obj).text;
465 local old_close = getmtable(obj).close;
466 local underlying_object = underlying;
468 getmtable(obj).name = function(obj)
469 return _name;
471 getmtable(obj).four_to_five = function(obj)
472 local res, err;
473 res, err = old_four_to_five(obj);
474 if not res then
475 return res, err;
477 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
479 getmtable(obj).deflate = function(obj)
480 local res, err;
481 res, err = old_deflate(obj);
482 if not res then
483 return res, err;
485 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
487 getmtable(obj).text = function(obj)
488 local res, err;
489 res, err = old_text(obj);
490 if not res then
491 return res, err;
493 return inject_text_output(res, obj, "text<" .. _name .. ">");
495 getmtable(obj).close = function(obj)
496 local ret, err, ret2, err2;
497 ret, err = old_close(obj);
498 if underlying_object then ret2, err2 = underlying_object:close(); end
499 if ret and not ret2 then
500 err = err2;
501 ret = ret2;
503 return ret, err;
505 getmtable(obj).__index = function(tab, name)
506 local x = getmtable(obj)[name];
507 if x then
508 return x;
510 error("Invalid method " .. name .. " for BinaryOutput");
512 return obj;
515 inject_text_input = function(obj, underlying, name)
516 local _name = name;
517 local old_close = getmtable(obj).close;
518 local underlying_object = underlying;
520 getmtable(obj).lines = function(obj)
521 return function(state, prevline)
522 return state:read();
523 end, obj, nil;
525 getmtable(obj).name = function(obj)
526 return _name;
528 getmtable(obj).close = function(obj)
529 local ret, err, ret2, err2;
530 ret, err = old_close(obj);
531 if underlying_object then ret2, err2 = underlying_object:close(); end
532 if ret and not ret2 then
533 err = err2;
534 ret = ret2;
536 return ret, err;
538 getmtable(obj).__index = function(tab, name)
539 local x = getmtable(obj)[name];
540 if x then
541 return x;
543 error("Invalid method " .. name .. " for TextInput");
545 return obj;
548 inject_text_output = function(obj, underlying, name)
549 local _name = name;
550 local old_close = getmtable(obj).close;
551 local underlying_object = underlying;
553 getmtable(obj).name = function(obj)
554 return _name;
556 getmtable(obj).close = function(obj)
557 local ret, err, ret2, err2;
558 ret, err = old_close(obj);
559 if underlying_object then ret2, err2 = underlying_object:close(); end
560 if ret and underlying_object then
561 err = err2;
562 ret = ret2;
564 return ret, err;
566 getmtable(obj).__index = function(tab, name)
567 local x = getmtable(obj)[name];
568 if x then
569 return x;
571 error("Invalid method " .. name .. " for TextOutput");
573 return obj;
576 inject_archive_input = function(obj, name)
577 local _name = name;
578 local old_member = getmtable(obj).member;
579 local old_member_list = getmtable(obj).member_list;
580 getmtable(obj).member = function(obj, member)
581 local res, err;
582 res, err = old_member(obj, member);
583 if not res then
584 return res, err;
586 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
588 getmtable(obj).name = function(obj)
589 return _name;
591 getmtable(obj).member_list = function(obj)
592 local tab = old_member_list(obj);
593 if tab then table.sort(tab, jpcrr.stringlessthan); end
594 return tab;
596 getmtable(obj).__index = function(tab, name)
597 local x = getmtable(obj)[name];
598 if x then
599 return x;
601 error("Invalid method " .. name .. " for ArchiveInput");
603 return obj;
606 inject_archive_output = function(obj, name)
607 local _name = name;
608 local old_member = getmtable(obj).member;
609 getmtable(obj).member = function(obj, member)
610 local res, err;
611 res, err = old_member(obj, member);
612 if not res then
613 return res, err;
615 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
617 getmtable(obj).name = function(obj)
618 return _name;
620 getmtable(obj).__index = function(tab, name)
621 local x = getmtable(obj)[name];
622 if x then
623 return x;
625 error("Invalid method " .. name .. " for ArchiveOutput");
627 return obj;
631 -- Redefined print.
633 local rprint = print_console_msg;
634 print_console_msg = nil;
635 print = function(...)
636 local x = "";
637 local y = {...};
638 local i;
639 for i = 1,#y do
640 if i > 1 then
641 x = x .. "\t" .. toString(y[i]);
642 else
643 x = toString(y[i]);
646 rprint(x);
648 print_console_msg = nil;
651 -- I/O routines.
652 local stringfind = string.find;
653 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
654 local path = args["luapath"] or ".";
655 local toresourcename = function(resname)
656 if not resname then
657 return randname(path .. "/", "luatemp-");
660 if not stringfind(resname, "[%d%l%u_%-]") then
661 error("Bad resource name (case 1): " .. resname);
663 if stringfind(resname, "^/") then
664 error("Bad resource name (case 2): " .. resname);
666 if stringfind(resname, "%.%.") then
667 error("Bad resource name (case 3): " .. resname);
669 if stringfind(resname, "\\") then
670 error("Bad resource name (case 4): " .. resname);
673 return resname, path .. "/" .. resname;
678 local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
679 local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
680 local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
681 local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
682 local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
684 local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
685 local mkdir = baseFS.mkdir;
686 local unlink = baseFS.unlink;
687 local rename = baseFS.rename;
689 local getmtable = getmetatable;
691 loadfile = function(_script)
692 local file, file2, err, content;
693 local x, y;
694 x, y = toresourcename(_script);
695 file, err = openbinin(y, "r");
696 if not file then
697 return nil, "Can't open " .. _script .. ": " .. err;
699 file2, err = file:text();
700 if not file2 then
701 return nil, "Can't transform " .. _script .. ": " .. err;
703 content = "";
704 line = file2:read();
705 while line do
706 content = content .. line .. "\n";
707 line = file2:read();
709 file2:close();
710 file:close();
711 return loadstring(content, _script);
714 io.open = function(name, mode)
715 local _name;
716 local res, err;
717 local y;
718 _name, y = toresourcename(name);
719 res, err = openbinary(y, mode);
720 if not res then
721 return res, err;
723 return inject_binary_file(res, _name);
726 io.open_arch_read = function(name)
727 local _name = name;
728 local res, err;
729 local y;
730 _name, y = toresourcename(name);
731 res, err = openarchin(y);
732 if not res then
733 return res, err;
735 return inject_archive_input(res, _name);
738 io.open_arch_write = function(name)
739 local _name = name;
740 local res, err;
741 local y;
742 _name, y = toresourcename(name);
743 res, err = openarchout(y);
744 if not res then
745 return res, err;
747 return inject_archive_output(res, _name);
750 io.open_read = function(name)
751 local _name = name;
752 local res, err;
753 local y;
754 _name, y = toresourcename(name);
755 res, err = openbinin(y);
756 if not res then
757 return res, err;
759 return inject_binary_input(res, nil, _name);
762 io.open_write = function(name)
763 local _name = name;
764 local res, err;
765 local y;
766 _name, y = toresourcename(name);
767 res, err = openbinout(y);
768 if not res then
769 return res, err;
771 return inject_binary_output(res, nil, _name);
774 io.mkdir = function(name)
775 local _name, y;
776 _name, y = toresourcename(name);
777 if mkdir(y) then
778 return _name;
779 else
780 return nil;
784 io.unlink = function(name)
785 local _name, y;
786 _name, y = toresourcename(name);
787 if unlink(y) then
788 return _name;
789 else
790 return nil;
794 io.rename = function(name1, name2)
795 local _name, y;
796 local _name2, y2;
797 _name, y = toresourcename(name1);
798 _name2, y2 = toresourcename(name2);
799 if rename(y, y2) then
800 return _name, _name2;
801 else
802 return nil;
806 io.transform = {};
808 io.transform.text = function()
809 return function(obj)
810 return obj:text();
814 io.transform.four_to_five = function()
815 return function(obj)
816 return obj:four_to_five();
820 io.transform.inflate = function()
821 return function(obj)
822 return obj:inflate();
826 io.transform.deflate = function()
827 return function(obj)
828 return obj:deflate();
832 io.dotransform = function(obj, ...)
833 local todo = {...};
834 local k, v;
835 local obj2, err;
836 for k, v in ipairs(todo) do
837 obj2, err = v(obj);
838 if not obj2 then
839 obj:close();
840 return nil, err;
842 obj = obj2;
844 return obj;
847 io.dotransform2 = function(obj, err, ...)
848 if not obj then
849 return obj, err;
851 return io.dotransform(obj, err, ...);
856 jpcrr.next_frame = function(name)
857 while true do
858 if not jpcrr.pc_connected() then
859 jpcrr.wait_pc_attach();
861 if jpcrr.in_frame_hold() then
862 jpcrr.release_vga();
864 if jpcrr.wait_vga() then
865 return;
871 -- Various stuff built on top of ECI.
872 local invoke = jpcrr.invoke;
873 local invokecall = jpcrr.call;
874 local invokesync = jpcrr.invoke_synchronous;
876 jpcrr.save_state = function(name)
877 local _name, _fname;
878 _name, _fname = toresourcename(name);
879 invokesync("state-save", {_fname});
880 return _name;
883 jpcrr.save_movie = function(name)
884 local _name, _fname;
885 _name, _fname = toresourcename(name);
886 invokesync("movie-save", {_name});
887 return _name;
890 jpcrr.load_state_normal = function(name)
891 local _name, _fname;
892 _name, _fname = toresourcename(name);
893 invokesync("state-load", {_name});
894 return _name;
897 jpcrr.load_state_preserve_events = function(name)
898 local _name, _fname;
899 _name, _fname = toresourcename(name);
900 invokesync("state-load-noevents", {_name});
901 return _name;
904 jpcrr.load_state_movie = function(name)
905 local _name, _fname;
906 _name, _fname = toresourcename(name);
907 invokesync("state-load-movie", {_name});
908 return _name;
911 jpcrr.assemble = function()
912 invokesync("pc-assemble");
915 jpcrr.change_authors = function()
916 invokesync("change-authors");
919 jpcrr.ram_dump = function(name, binary)
920 local _name, _fname;
921 _name, _fname = toresourcename(name);
922 if binary then
923 invokesync("ram-dump-binary", {_name});
924 else
925 invokesync("ram-dump-text", {_name});
927 return _name;
930 jpcrr.hud.left_gap = function(f, g)
931 invoke("hud-left-gap", {toString(f), toString(g)});
934 jpcrr.hud.right_gap = function(f, g)
935 invoke("hud-right-gap", {toString(f), toString(g)});
938 jpcrr.hud.top_gap = function(f, g)
939 invoke("hud-top-gap", {toString(f), toString(g)});
942 jpcrr.hud.bottom_gap = function(f, g)
943 invoke("hud-bottom-gap", {toString(f), toString(g)});
946 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
947 invoke("hud-white-solid-box", {toString(f), toString(x), toString(y), toString(w), toString(h)});
950 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
951 invoke("hud-box", {toString(f), toString(x), toString(y), toString(w), toString(h),
952 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
953 toString(fg), tostring(fb), toString(fa)});
956 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
957 invoke("hud-circle", {toString(f), toString(x), toString(y), toString(r),
958 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
959 toString(fg), tostring(fb), toString(fa)});
962 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
963 invoke("hud-bitmap", {toString(f), toString(x), toString(y), bmap, toString(lr),
964 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
965 toString(fa)});
968 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
969 invoke("hud-bitmap-binary", {toString(f), toString(x), toString(y), bmap, toString(lr),
970 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
971 toString(fa)});
974 jpcrr.set_pccontrol_pos = function(x, y)
975 invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
978 jpcrr.set_luaplugin_pos = function(x, y)
979 invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
982 jpcrr.set_pcmonitor_pos = function(x, y)
983 invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
986 jpcrr.set_pcstartstoptest_pos = function(x, y)
987 invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
990 jpcrr.set_virtualkeyboard_pos = function(x, y)
991 invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
994 jpcrr.exit = function()
995 invokesync("luaplugin-terminate");
998 jpcrr.pc_start = function()
999 invoke("pc-start");
1002 jpcrr.pc_stop = function()
1003 invokesync("pc-stop");
1006 jpcrr.screenshot = function(include_hud)
1007 if include_hud then
1008 invoke("screenshot-renderbuffer");
1009 else
1010 invoke("screenshot-vgabuffer");
1015 jpcrr.vretrace_start_trap = function(is_on)
1016 if is_on then
1017 invokesync("trap-vretrace-start-on");
1018 else
1019 invokesync("trap-vretrace-start-off");
1023 jpcrr.vretrace_end_trap = function(is_on)
1024 if is_on then
1025 invokesync("trap-vretrace-end-on");
1026 else
1027 invokesync("trap-vretrace-end-off");
1031 jpcrr.timed_trap = function(nsecs)
1032 if nsecs then
1033 invokesync("trap-timed", {toString(nsecs)});
1034 else
1035 invokesync("trap-timed-disable");
1039 jpcrr.write_byte = function(addr, value)
1040 invokesync("memory-write", {toString(addr), toString(value), "1"});
1043 jpcrr.write_word = function(addr, value)
1044 invokesync("memory-write", {toString(addr), toString(value), "2"});
1047 jpcrr.write_dword = function(addr, value)
1048 invokesync("memory-write", {toString(addr), toString(value), "4"});
1051 jpcrr.read_byte = function(addr)
1052 local t = {toString(addr), "1"};
1053 t = invokecall("memory-read", t);
1054 return (t or {})[1];
1057 jpcrr.read_word = function(addr)
1058 local t = {toString(addr), "2"};
1059 t = invokecall("memory-read", t);
1060 return (t or {})[1];
1063 jpcrr.read_dword = function(addr)
1064 local t = {toString(addr), "4"};
1065 t = invokecall("memory-read", t);
1066 return (t or {})[1];
1069 jpcrr.invoke = nil;
1070 jpcrr.invoke_synchronous = nil;
1071 jpcrr.call = null
1073 -- Dofile.
1074 dofile = function(_script)
1075 local chunk, err, indication
1076 chunk, err = loadfile(_script);
1077 if not chunk then
1078 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1080 return chunk();
1083 local args2 = args;
1084 args = null;
1085 args = {};
1086 for k, v in pairs(args2) do
1087 if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1088 args[string.sub(k, 3)] = v;
1091 jpcrr_raw = null;
1094 chunk = null;
1095 loaded, err = pcall(function()
1096 chunk, err = loadfile(script);
1097 if not chunk then
1098 error(err);
1100 end);
1101 if not loaded then
1102 print("Kernel: Can't load script " .. script .. ": " .. err);
1103 invoke("luaplugin-terminate");
1104 while true do end
1107 script = null;
1108 indication, err = pcall(chunk);
1109 if not indication then
1110 print("Kernel: Unprotected error in script: " .. err);
1111 invoke("luaplugin-terminate");
1112 while true do end