New Lua functions
[jpcrr.git] / luakernel.lua
blobf4b9b3d9436292d47a31cf164f9e9853e3d564d7
1 --
2 -- Copyright 2009-2010 Ilari Liusvaara
3 --
4 -- Licenced under GNU GPL v2.
5 --
7 -- Exported tables:
8 -- - args
9 -- Contains user-level arguments.
11 -- Exported functions:
12 -- - All lua standard functions in tables main, "coroutine", "string" and "table".
13 -- - modulus_split(number num, number...)
14 -- Returns quotents and quotent remainders of number divided by given dividers.
15 -- The number of results returned is equal to number of numbers passed. The
16 -- dividers must be in decreasing order and all dividers must be nonzero and
17 -- should be >1.
18 -- - assert(object ret, object err)
19 -- If ret is considered true, return ret. Otherwise raise err as error. Exception
20 -- if err is nil too, then ret is returned anyway.
21 -- - bit.none(number...)
22 -- Returns 48-bit number that has those bits set that are set in none of its
23 -- arguments.
24 -- - bit.any(number...)
25 -- Returns 48-bit number that has those bits set that are set in any of its
26 -- arguments.
27 -- - bit.parity(number...)
28 -- Returns 48-bit number that has those bits set that are set in even number
29 -- of its arguments.
30 -- - bit.any(number...)
31 -- Returns 48-bit number that has those bits set that are set in all of its
32 -- arguments.
33 -- - bit.lshift(number num, number shift)
34 -- Returns 48 rightmost bits of num shifted by shift places left. Going outside
35 -- shift range 0-47 produces unpredicatable results.
36 -- - bit.rshift(number num, number shift)
37 -- Returns 48 rightmost bits of num shifted by shift places right. Going outside
38 -- shift range 0-47 produces unpredicatable results.
39 -- - bit.arshift(number num, number shift)
40 -- Returns 48 rightmost bits of num shifted by shift places right and bit 47
41 -- value copied to all incoming bits. Going outside shift range 0-47 produces
42 -- unpredicatable results.
43 -- - bit.add(number...)
44 -- Returns sum of all passed numbers modulo 2^48.
45 -- - bit.addneg(number...)
46 -- Returns 0 minus sum of all passed numbers modulo 2^48.
47 -- - bit.addalt(number...)
48 -- Returns sum of odd arguments (first is odd) minus sum of even arguments modulo
49 -- 2^48.
50 -- - bit.rol(number num, number shift)
51 -- Returns 48 rightmost bits of num rotated by shift places left. Going outside
52 -- shift range 0-47 produces unpredicatable results.
53 -- - bit.ror(number num, number shift)
54 -- Returns 48 rightmost bits of num rotated by shift places right. Going outside
55 -- shift range 0-47 produces unpredicatable results.
56 -- - bit.bswap2(number num)
57 -- Returns 16 rightmost bits of num byte-swapped.
58 -- - bit.bswap3(number num)
59 -- Returns 24 rightmost bits of num byte-swapped.
60 -- - bit.bswap4(number num)
61 -- Returns 32 rightmost bits of num byte-swapped.
62 -- - bit.bswap5(number num)
63 -- Returns 40 rightmost bits of num byte-swapped.
64 -- - bit.bswap6(number num)
65 -- Returns 48 rightmost bits of num byte-swapped.
66 -- - bit.signextend(number num, number bitnum)
67 -- Copy bitnum'th bit of num to all higher bits of num and return result. Going
68 -- outside bitnum range of 0-47 produces unpredictable results.
69 -- - bit.tosigned(number num, number bitnum)
70 -- Mask off bitnum'th bit and all higher bits. If bitnum'th bit of num was set,
71 -- perform 2s complement on number and negate the result.
72 -- - bit.tohex(number num)
73 -- Returns hexadecimal string representation of number.
74 -- - jpcrr.wait_message()
75 -- Waits for message (string) to come from message queue. Reutrns nil if interrupted.
76 -- - jpcrr.poll_message()
77 -- Checks if there is message from message queue. Reutrns message if there is one,
78 -- nil if none.
79 -- - jpcrr.wait_pc_stop()
80 -- Waits for PC execution to stop (but does not attempt to actually stop it).
81 -- If script is in frame hold, the frame hold is released.
82 -- Returns true if execution got stopped, false if interrupted.
83 -- - jpcrr.pc_running()
84 -- Returns true if PC is running.
85 -- - jpcrr.clock_time()
86 -- Returns current time or nil if no PC.
87 -- - jpcrr.pc_connected()
88 -- Returns true if PC is connected.
89 -- - jpcrr.wait_pc_attach()
90 -- Wait for PC to attach.
91 -- - jpcrr.next_frame()
92 -- Wait for next frame output hold.
93 -- - jpcrr.in_frame_hold()
94 -- Returns true if in frame hold, false otherwise.
95 -- - jpcrr.keypressed(number key)
96 -- Return true if key is pressed, else false.
97 -- - jpcrr.wait_vga()
98 -- Waits for VGA to enter frame hold mode. Frame hold happens once per frame.
99 -- - jpcrr.release_vga()
100 -- Allow VGA to exit frame hold mode. Wait for frame hold first.
101 -- - jpcrr.vga_resolution()
102 -- Return VGA x and y resolutions. -1x-1 or 0x0 is returned if no valid resolution.
103 -- Should only be called during frame hold.
104 -- - jpcrr.hud.left_gap(number flags, number gap)
105 -- Set left gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
106 -- 1 (2) is set, dump to video dump.
107 -- - jpcrr.hud.right_gap(number flags, number gap)
108 -- Set right gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
109 -- 1 (2) is set, dump to video dump.
110 -- - jpcrr.hud.top_gap(number flags, number gap)
111 -- Set top gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
112 -- 1 (2) is set, dump to video dump.
113 -- - jpcrr.hud.bottom_gap(number flags, number gap)
114 -- Set bottom gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
115 -- 1 (2) is set, dump to video dump.
116 -- - jpcrr.hud.white_solid_box(number flags, number x, number y, number w, number h)
117 -- Draw with solid opaque box.
118 -- - jpcrr.hud.box(number flags, number x, number y, number w, number h, number linethick,
119 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
120 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
121 -- Draw box with specified size, border line thickness, line color and fill color.
122 -- - jpcrr.hud.circle(number flags, number x, number y, number r, number linethick,
123 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
124 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
125 -- Draw circle with specified size, border line thickness, line color and fill color.
126 -- - jpcrr.hud.bitmap(number flags, number x, number y, string bmap,
127 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
128 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
129 -- Draw bitmap with specified foreground color and background color.
130 -- - jpcrr.hud.bitmap_binary(number flags, number x, number y, string bmap,
131 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
132 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
133 -- Draw binary bitmap with specified foreground color and background color.
134 -- - jpcrr.joystick_state()
135 -- Returns nil if no joystick. Otherwise returns hold times for all four axis (numeric)
136 -- followed by button states (boolean).
137 -- - jpcrr.keyboard_leds()
138 -- Returns nil if no keyboard, false if LED status is unknown. Otherwise returns three
139 -- booleans, first being state of num lock, second being state of caps lock and third
140 -- being state of scroll lock.
141 -- - jpcrr.mouse_state()
142 -- Returns nil if no mouse. Otherwise returns X, Y and Z axis pending motions (numeric)
143 -- followed by button states (5 booleans).
144 -- - jpcrr.component_encode(table components)
145 -- Return component encoding for specified components.
146 -- - jpcrr.component_decode(string line)
147 -- Return component decoding for specified line, nil/nil if it doesn't encode
148 -- anything, nil/string if parse error occurs (the error is the second return).
149 -- - jpcrr.save_state(string name)
150 -- Savestate into specified file. Returns name used.
151 -- - jpcrr.save_movie(string name)
152 -- Save movie into specified file. Returns name used.
153 -- - jpcrr.load_state_normal(string name)
154 -- Load specified savestate. Returns name used.
155 -- - jpcrr.load_state_preserve_events(string name)
156 -- Load specified savestate, preserving events. Returns name used.
157 -- - jpcrr.load_state_movie(string name)
158 -- Load specified savestate as movie. Returns name used.
159 -- - jpcrr.assemble()
160 -- Open system settings dialog.
161 -- - jpcrr.change_authors()
162 -- Open change authors dialog.
163 -- - jpcrr.exit = function()
164 -- Exit the Lua VM.
165 -- - jpcrr.ram_dump(string name, boolean binary)
166 -- Dump PC memory to specified file. If binary is true, dump is binary, otherwise
167 -- textual hexadecimal dump.
168 -- - jpcrr.write_byte(number addr, number value)
169 -- Write byte to specified physical address.
170 -- - jpcrr.write_word(number addr, number value)
171 -- Write word to specified physical address (little endian).
172 -- - jpcrr.write_dword(number addr, number value)
173 -- Write dword to specified physical address (little endian).
174 -- - jpcrr.read_byte(number addr)
175 -- Return byte from specified physical address.
176 -- - jpcrr.read_word(number addr)
177 -- Return word from specified physical address (little endian).
178 -- - jpcrr.read_dword(number addr)
179 -- Return dword from specified physical address (little endian).
180 -- - jpcrr.read_byte_signed(number addr)
181 -- Return signed byte from specified physical address.
182 -- - jpcrr.read_word_signed(number addr)
183 -- Return signed word from specified physical address (little endian).
184 -- - jpcrr.read_dword_signed(number addr)
185 -- Return signed dword from specified physical address (little endian).
186 -- - jpcrr.timed_trap(number nsecs)
187 -- Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
188 -- - jpcrr.vretrace_start_trap(boolean is_on)
189 -- Set trap on vretrace start on/off.
190 -- - jpcrr.vretrace_end_trap(boolean is_on)
191 -- Set trap on vretrace end on/off.
192 -- - jpcrr.pc_start()
193 -- Start PC execution.
194 -- - jpcrr.pc_stop()
195 -- Stop PC execution.
196 -- - jpcrr.set_pccontrol_pos(number x, number y)
197 -- Set position of PCControl window.
198 -- - jpcrr.set_luaplugin_pos(number x, number y)
199 -- Set position of LuaPlugin window.
200 -- - jpcrr.set_pcmonitor_pos(number x, number y)
201 -- Set position of PCMonitor window.
202 -- - jpcrr.set_pcstartstoptest_pos(number x, number y)
203 -- Set position of PCStartStopTest window.
204 -- - jpcrr.set_virtualkeyboard_pos(number x, number y)
205 -- Set position of VirtualKeyboard window.
206 -- - jpcrr.stringlessthan(String x, String y)
207 -- Return true if x is before y in codepoint lexical order, otherwise false.
208 -- - jpcrr.screenshot(boolean include_hud)
209 -- Take screen shot (Requires monitor). If include_hud is true, include HUD
210 -- (as shown on screen). Note that this should only be called during frame
211 -- hold or results are pretty much undefined.
212 -- - jpcrr.sendevent(string/number...)
213 -- Sends specified event.
215 -- I/O functions have the following conventions. If function returns any real data, the first
216 -- return value returns this data or is nil. Otherwise first return value is true or false.
217 -- If first return value is nil or false, then the second return value gives textual error
218 -- message for failed operation, or is nil if EOF occured before anything was read.
220 -- Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
221 -- success or failure.
223 -- Specifying nil as name of file results random filename being used (it even works with unlink,
224 -- mkdir, rename and read-only access, but doesn't make any sense there).
226 -- Class: BinaryFile:
227 -- Binary file for RO or RW access. Methods are as follows:
228 -- - name()
229 -- Return name of file.
230 -- - length()
231 -- Return length of file.
232 -- - set_length(number length)
233 -- Truncate file to specified length
234 -- - read(number offset, number length)
235 -- Read up to length bytes from offset.
236 -- - write(number offset, string content)
237 -- Write content to specified offset.
238 -- - close()
239 -- Close the file.
240 -- Class: BinaryInput:
241 -- Binary file for sequential input. Methods are as follows:
242 -- - name()
243 -- Return name of file.
244 -- - four_to_five()
245 -- Return BinaryInput that is four to five decoding of this stream.
246 -- - text()
247 -- Return stream as TextInput.
248 -- - inflate()
249 -- Return BinaryInput that is inflate of this stream.
250 -- - read(number bytes)
251 -- Read up to bytes bytes from file.
252 -- - read()
253 -- Read the entiere file at once.
254 -- - close()
255 -- Close the file.
256 -- Character set for binary files is Latin-1.
258 -- Class: BinaryOutput:
259 -- Binary file for sequential output. Methods are as follows:
260 -- - name()
261 -- Return name of file.
262 -- - four_to_five()
263 -- Return BinaryOutput that writes four to five encoded output to this stream.
264 -- - text()
265 -- Return stream as TextOutput.
266 -- - deflate()
267 -- Return BinaryOutput that writes deflate output to this stream.
268 -- - write(string content)
269 -- Write string to file.
270 -- - close()
271 -- Close the file.
272 -- Character set for binary files is Latin-1.
274 -- Class: TextInput:
275 -- - name()
276 -- Return name of file.
277 -- - read()
278 -- Read line from file.
279 -- - read_component()
280 -- Read next componented line into array.
281 -- - lines()
282 -- Line iterator function.
283 -- - close()
284 -- Close the file.
285 -- Character set for text files is UTF-8.
287 -- Class: TextOutput:
288 -- - name()
289 -- Return name of file.
290 -- - write(string line)
291 -- Write line line to file.
292 -- - write_component(table components)
293 -- Write componented line.
294 -- - close()
295 -- Close the file.
296 -- Character set for text files is UTF-8.
298 -- Class ArchiveIn:
299 -- - member(string name)
300 -- Open substream for member name. The methods are the same as for io.opentextin.
301 -- - member_binary(string name)
302 -- Open binary (four to five) substream for member name. The methods are the same as
303 -- for io.openbinaryin.
304 -- - close()
305 -- Close the file. Any opened substreams are invalidated.
306 -- - member_list()
307 -- Return table listing all members of archive (sorted by name).
308 -- Class ArchiveOut:
309 -- - member(string name)
310 -- Open substream for member name. The methods are the same as for io.opentextout. Note that
311 -- previous member must be closed before next can open.
312 -- - member_binary(string name)
313 -- Open binary (four to five) substream for member name. The methods are the same as
314 -- for io.openbinaryout. Note that previous substream must be closed before next can open.
315 -- - commit()
316 -- Commit the file. No substream may be open. Closes the file.
317 -- - rollback()
318 -- Rollback the file. No substream may be open. Closes the file.
320 -- - io.open(string name, string mode) -> BinaryFile
321 -- Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
322 -- write).
323 -- - io.open_read(string name) -> BinaryInput
324 -- Open file named @name as binary input stream.
325 -- - io.open_write(string name) -> BinaryOutput
326 -- Open file named @name as binary input stream.
327 -- - io.open_arch_read(string name) -> ArchiveIn
328 -- Open file named @name as input archive.
329 -- - io.open_arch_write(string name) -> ArchiveOut
330 -- Open file named @name as output archive.
331 -- - io.mkdir(string name)
332 -- Create directory name. Returns name created on success, nil on failure.
333 -- - io.unlink(string name)
334 -- Delete file/directory name. Returns name deleted on success, nil on failure.
335 -- - io.rename(string old, string new)
336 -- Rename file old -> new. Returns old, new on success, nil on failure.
337 -- - io.transform.text()
338 -- Returns function that calls text() method of its parameter.
339 -- - io.transform.four_to_five()
340 -- Returns function that calls four_to_five() method of its parameter.
341 -- - io.transform.deflate()
342 -- Returns function that calls deflate() method of its parameter.
343 -- - io.transform.inflate()
344 -- Returns function that calls inflate() method of its parameter.
345 -- - io.dotransform(object obj, function...)
346 -- Call specified functions on specified object. If any function fails (first argument nil
347 -- or false), call close method on preceeding object. Otherwise call specified functions
348 -- chained left to right and return the result.
349 -- - io.dotransform2(object obj, string err, function...)
350 -- Similar to dotransform except if obj is nil or false, returns obj, err.
356 local handle, err, chunk, indication, k, v;
358 local loadmod = loadmodule;
359 loadmodule = nil;
361 local export_module_in = function(tab, modname, prefix)
362 local fun = loadmod(modname);
363 for k, v in pairs(fun) do
364 tab[(prefix or "") .. k] = v;
368 jpcrr = {};
369 jpcrr.hud = {};
370 bit = {};
371 io = {};
373 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
374 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
375 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
376 export_module_in(bit, "org.jpc.luaextensions.Bitops");
378 -- Few misc functions.
379 assert = function(val, err)
380 if (not val) and err then
381 error(err);
383 return val;
386 modulus_split = function(number, ...)
387 local dividers = {...};
388 local results = {};
389 local rem;
391 for k, v in ipairs(dividers) do
392 rem = number % v;
393 table.insert(results, (number - rem) / v);
394 number = rem;
397 table.insert(results, number);
398 return unpack(results);
401 local getmtable = getmetatable;
402 local toString = tostring;
403 local inject_binary_file;
404 local inject_binary_input;
405 local inject_binary_output;
406 local inject_text_input;
407 local inject_text_output;
408 local inject_archive_input;
409 local inject_archive_output;
411 -- Class member injectors.
412 inject_binary_file = function(obj, name)
413 local _name = name;
414 getmtable(obj).name = function(obj)
415 return _name;
417 getmtable(obj).__index = function(tab, name)
418 local x = getmtable(obj)[name];
419 if x then
420 return x;
422 error("Invalid method " .. name .. " for BinaryFile");
424 return obj;
427 inject_binary_input = function(obj, underlying, name)
428 local _name = name;
429 local old_four_to_five = getmtable(obj).four_to_five;
430 local old_inflate = getmtable(obj).inflate;
431 local old_text = getmtable(obj).text;
432 local old_read = getmtable(obj).read;
433 local old_close = getmtable(obj).close;
434 local underlying_object = underlying;
436 getmtable(obj).name = function(obj)
437 return _name;
439 getmtable(obj).four_to_five = function(obj)
440 local res, err;
441 res, err = old_four_to_five(obj);
442 if not res then
443 return res, err;
445 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
447 getmtable(obj).inflate = function(obj)
448 local res, err;
449 res, err = old_inflate(obj);
450 if not res then
451 return res, err;
453 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
455 getmtable(obj).text = function(obj)
456 local res, err;
457 res, err = old_text(obj);
458 if not res then
459 return res, err;
461 return inject_text_input(res, obj, "text<" .. _name .. ">");
463 getmtable(obj).read = function(obj, toread)
464 if toread then
465 return old_read(obj, toread);
466 else
467 local res = "";
468 local ret, err;
469 while true do
470 ret, err = old_read(obj, 16384);
471 if not ret then
472 if not err then
473 return res;
475 return nil, err;
477 res = res .. ret;
481 getmtable(obj).close = function(obj)
482 local ret, err, ret2, err2;
483 ret, err = old_close(obj);
484 if underlying_object then ret2, err2 = underlying_object:close(); end
485 if ret and not ret2 then
486 err = err2;
487 ret = ret2;
489 return ret, err;
491 getmtable(obj).__index = function(tab, name)
492 local x = getmtable(obj)[name];
493 if x then
494 return x;
496 error("Invalid method " .. name .. " for BinaryInput");
498 return obj;
501 inject_binary_output = function(obj, underlying, name)
502 local _name = name;
503 local old_four_to_five = getmtable(obj).four_to_five;
504 local old_deflate = getmtable(obj).deflate;
505 local old_text = getmtable(obj).text;
506 local old_close = getmtable(obj).close;
507 local underlying_object = underlying;
509 getmtable(obj).name = function(obj)
510 return _name;
512 getmtable(obj).four_to_five = function(obj)
513 local res, err;
514 res, err = old_four_to_five(obj);
515 if not res then
516 return res, err;
518 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
520 getmtable(obj).deflate = function(obj)
521 local res, err;
522 res, err = old_deflate(obj);
523 if not res then
524 return res, err;
526 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
528 getmtable(obj).text = function(obj)
529 local res, err;
530 res, err = old_text(obj);
531 if not res then
532 return res, err;
534 return inject_text_output(res, obj, "text<" .. _name .. ">");
536 getmtable(obj).close = function(obj)
537 local ret, err, ret2, err2;
538 ret, err = old_close(obj);
539 if underlying_object then ret2, err2 = underlying_object:close(); end
540 if ret and not ret2 then
541 err = err2;
542 ret = ret2;
544 return ret, err;
546 getmtable(obj).__index = function(tab, name)
547 local x = getmtable(obj)[name];
548 if x then
549 return x;
551 error("Invalid method " .. name .. " for BinaryOutput");
553 return obj;
556 inject_text_input = function(obj, underlying, name)
557 local _name = name;
558 local old_close = getmtable(obj).close;
559 local underlying_object = underlying;
561 getmtable(obj).lines = function(obj)
562 return function(state, prevline)
563 return state:read();
564 end, obj, nil;
566 getmtable(obj).name = function(obj)
567 return _name;
569 getmtable(obj).close = function(obj)
570 local ret, err, ret2, err2;
571 ret, err = old_close(obj);
572 if underlying_object then ret2, err2 = underlying_object:close(); end
573 if ret and not ret2 then
574 err = err2;
575 ret = ret2;
577 return ret, err;
579 getmtable(obj).__index = function(tab, name)
580 local x = getmtable(obj)[name];
581 if x then
582 return x;
584 error("Invalid method " .. name .. " for TextInput");
586 return obj;
589 inject_text_output = function(obj, underlying, name)
590 local _name = name;
591 local old_close = getmtable(obj).close;
592 local underlying_object = underlying;
594 getmtable(obj).name = function(obj)
595 return _name;
597 getmtable(obj).close = function(obj)
598 local ret, err, ret2, err2;
599 ret, err = old_close(obj);
600 if underlying_object then ret2, err2 = underlying_object:close(); end
601 if ret and underlying_object then
602 err = err2;
603 ret = ret2;
605 return ret, err;
607 getmtable(obj).__index = function(tab, name)
608 local x = getmtable(obj)[name];
609 if x then
610 return x;
612 error("Invalid method " .. name .. " for TextOutput");
614 return obj;
617 inject_archive_input = function(obj, name)
618 local _name = name;
619 local old_member = getmtable(obj).member;
620 local old_member_list = getmtable(obj).member_list;
621 getmtable(obj).member = function(obj, member)
622 local res, err;
623 res, err = old_member(obj, member);
624 if not res then
625 return res, err;
627 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
629 getmtable(obj).name = function(obj)
630 return _name;
632 getmtable(obj).member_list = function(obj)
633 local tab = old_member_list(obj);
634 if tab then table.sort(tab, jpcrr.stringlessthan); end
635 return tab;
637 getmtable(obj).__index = function(tab, name)
638 local x = getmtable(obj)[name];
639 if x then
640 return x;
642 error("Invalid method " .. name .. " for ArchiveInput");
644 return obj;
647 inject_archive_output = function(obj, name)
648 local _name = name;
649 local old_member = getmtable(obj).member;
650 getmtable(obj).member = function(obj, member)
651 local res, err;
652 res, err = old_member(obj, member);
653 if not res then
654 return res, err;
656 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
658 getmtable(obj).name = function(obj)
659 return _name;
661 getmtable(obj).__index = function(tab, name)
662 local x = getmtable(obj)[name];
663 if x then
664 return x;
666 error("Invalid method " .. name .. " for ArchiveOutput");
668 return obj;
672 -- Redefined print.
674 local rprint = print_console_msg;
675 print_console_msg = nil;
676 print = function(...)
677 local x = "";
678 local y = {...};
679 local i;
680 for i = 1,#y do
681 if i > 1 then
682 x = x .. "\t" .. toString(y[i]);
683 else
684 x = toString(y[i]);
687 rprint(x);
689 print_console_msg = nil;
692 -- I/O routines.
693 local stringfind = string.find;
694 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
695 local path = args["luapath"] or ".";
696 local toresourcename = function(resname)
697 if not resname then
698 return randname(path .. "/", "luatemp-");
701 if not stringfind(resname, "[%d%l%u_%-]") then
702 error("Bad resource name (case 1): " .. resname);
704 if stringfind(resname, "^/") then
705 error("Bad resource name (case 2): " .. resname);
707 if stringfind(resname, "%.%.") then
708 error("Bad resource name (case 3): " .. resname);
710 if stringfind(resname, "\\") then
711 error("Bad resource name (case 4): " .. resname);
714 return resname, path .. "/" .. resname;
719 local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
720 local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
721 local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
722 local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
723 local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
725 local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
726 local mkdir = baseFS.mkdir;
727 local unlink = baseFS.unlink;
728 local rename = baseFS.rename;
730 local getmtable = getmetatable;
732 loadfile = function(_script)
733 local file, file2, err, content;
734 local x, y;
735 x, y = toresourcename(_script);
736 file, err = openbinin(y, "r");
737 if not file then
738 return nil, "Can't open " .. _script .. ": " .. err;
740 file2, err = file:text();
741 if not file2 then
742 return nil, "Can't transform " .. _script .. ": " .. err;
744 content = "";
745 line = file2:read();
746 while line do
747 content = content .. line .. "\n";
748 line = file2:read();
750 file2:close();
751 file:close();
752 return loadstring(content, _script);
755 io.open = function(name, mode)
756 local _name;
757 local res, err;
758 local y;
759 _name, y = toresourcename(name);
760 res, err = openbinary(y, mode);
761 if not res then
762 return res, err;
764 return inject_binary_file(res, _name);
767 io.open_arch_read = function(name)
768 local _name = name;
769 local res, err;
770 local y;
771 _name, y = toresourcename(name);
772 res, err = openarchin(y);
773 if not res then
774 return res, err;
776 return inject_archive_input(res, _name);
779 io.open_arch_write = function(name)
780 local _name = name;
781 local res, err;
782 local y;
783 _name, y = toresourcename(name);
784 res, err = openarchout(y);
785 if not res then
786 return res, err;
788 return inject_archive_output(res, _name);
791 io.open_read = function(name)
792 local _name = name;
793 local res, err;
794 local y;
795 _name, y = toresourcename(name);
796 res, err = openbinin(y);
797 if not res then
798 return res, err;
800 return inject_binary_input(res, nil, _name);
803 io.open_write = function(name)
804 local _name = name;
805 local res, err;
806 local y;
807 _name, y = toresourcename(name);
808 res, err = openbinout(y);
809 if not res then
810 return res, err;
812 return inject_binary_output(res, nil, _name);
815 io.mkdir = function(name)
816 local _name, y;
817 _name, y = toresourcename(name);
818 if mkdir(y) then
819 return _name;
820 else
821 return nil;
825 io.unlink = function(name)
826 local _name, y;
827 _name, y = toresourcename(name);
828 if unlink(y) then
829 return _name;
830 else
831 return nil;
835 io.rename = function(name1, name2)
836 local _name, y;
837 local _name2, y2;
838 _name, y = toresourcename(name1);
839 _name2, y2 = toresourcename(name2);
840 if rename(y, y2) then
841 return _name, _name2;
842 else
843 return nil;
847 io.transform = {};
849 io.transform.text = function()
850 return function(obj)
851 return obj:text();
855 io.transform.four_to_five = function()
856 return function(obj)
857 return obj:four_to_five();
861 io.transform.inflate = function()
862 return function(obj)
863 return obj:inflate();
867 io.transform.deflate = function()
868 return function(obj)
869 return obj:deflate();
873 io.dotransform = function(obj, ...)
874 local todo = {...};
875 local k, v;
876 local obj2, err;
877 for k, v in ipairs(todo) do
878 obj2, err = v(obj);
879 if not obj2 then
880 obj:close();
881 return nil, err;
883 obj = obj2;
885 return obj;
888 io.dotransform2 = function(obj, err, ...)
889 if not obj then
890 return obj, err;
892 return io.dotransform(obj, err, ...);
897 jpcrr.next_frame = function(name)
898 while true do
899 if not jpcrr.pc_connected() then
900 jpcrr.wait_pc_attach();
902 if jpcrr.in_frame_hold() then
903 jpcrr.release_vga();
905 if jpcrr.wait_vga() then
906 return;
912 -- Various stuff built on top of ECI.
913 local invoke = jpcrr.invoke;
914 local invokecall = jpcrr.call;
915 local invokesync = jpcrr.invoke_synchronous;
917 jpcrr.sendevent = function(...)
918 local arguments = {...};
919 local k, v;
920 for k, v in ipairs(arguments) do
921 arguments[k] = toString(v);
923 invokesync("sendevent", arguments);
926 jpcrr.save_state = function(name)
927 local _name, _fname;
928 _name, _fname = toresourcename(name);
929 invokesync("state-save", {_fname});
930 return _name;
933 jpcrr.save_movie = function(name)
934 local _name, _fname;
935 _name, _fname = toresourcename(name);
936 invokesync("movie-save", {_name});
937 return _name;
940 jpcrr.load_state_normal = function(name)
941 local _name, _fname;
942 _name, _fname = toresourcename(name);
943 invokesync("state-load", {_name});
944 return _name;
947 jpcrr.load_state_preserve_events = function(name)
948 local _name, _fname;
949 _name, _fname = toresourcename(name);
950 invokesync("state-load-noevents", {_name});
951 return _name;
954 jpcrr.load_state_movie = function(name)
955 local _name, _fname;
956 _name, _fname = toresourcename(name);
957 invokesync("state-load-movie", {_name});
958 return _name;
961 jpcrr.assemble = function()
962 invokesync("pc-assemble");
965 jpcrr.change_authors = function()
966 invokesync("change-authors");
969 jpcrr.ram_dump = function(name, binary)
970 local _name, _fname;
971 _name, _fname = toresourcename(name);
972 if binary then
973 invokesync("ram-dump-binary", {_name});
974 else
975 invokesync("ram-dump-text", {_name});
977 return _name;
980 jpcrr.hud.left_gap = function(f, g)
981 invoke("hud-left-gap", {toString(f), toString(g)});
984 jpcrr.hud.right_gap = function(f, g)
985 invoke("hud-right-gap", {toString(f), toString(g)});
988 jpcrr.hud.top_gap = function(f, g)
989 invoke("hud-top-gap", {toString(f), toString(g)});
992 jpcrr.hud.bottom_gap = function(f, g)
993 invoke("hud-bottom-gap", {toString(f), toString(g)});
996 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
997 invoke("hud-white-solid-box", {toString(f), toString(x), toString(y), toString(w), toString(h)});
1000 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
1001 invoke("hud-box", {toString(f), toString(x), toString(y), toString(w), toString(h),
1002 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
1003 toString(fg), tostring(fb), toString(fa)});
1006 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1007 invoke("hud-circle", {toString(f), toString(x), toString(y), toString(r),
1008 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
1009 toString(fg), tostring(fb), toString(fa)});
1012 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1013 invoke("hud-bitmap", {toString(f), toString(x), toString(y), bmap, toString(lr),
1014 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
1015 toString(fa)});
1018 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1019 invoke("hud-bitmap-binary", {toString(f), toString(x), toString(y), bmap, toString(lr),
1020 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
1021 toString(fa)});
1024 jpcrr.set_pccontrol_pos = function(x, y)
1025 invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
1028 jpcrr.set_luaplugin_pos = function(x, y)
1029 invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
1032 jpcrr.set_pcmonitor_pos = function(x, y)
1033 invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
1036 jpcrr.set_pcstartstoptest_pos = function(x, y)
1037 invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
1040 jpcrr.set_virtualkeyboard_pos = function(x, y)
1041 invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
1044 jpcrr.exit = function()
1045 invokesync("luaplugin-terminate");
1048 jpcrr.pc_start = function()
1049 invoke("pc-start");
1052 jpcrr.pc_stop = function()
1053 invokesync("pc-stop");
1056 jpcrr.screenshot = function(include_hud)
1057 if include_hud then
1058 invoke("screenshot-renderbuffer");
1059 else
1060 invoke("screenshot-vgabuffer");
1065 jpcrr.vretrace_start_trap = function(is_on)
1066 if is_on then
1067 invokesync("trap-vretrace-start-on");
1068 else
1069 invokesync("trap-vretrace-start-off");
1073 jpcrr.vretrace_end_trap = function(is_on)
1074 if is_on then
1075 invokesync("trap-vretrace-end-on");
1076 else
1077 invokesync("trap-vretrace-end-off");
1081 jpcrr.timed_trap = function(nsecs)
1082 if nsecs then
1083 invokesync("trap-timed", {toString(nsecs)});
1084 else
1085 invokesync("trap-timed-disable");
1089 jpcrr.write_byte = function(addr, value)
1090 invokesync("memory-write", {toString(addr), toString(value), "1"});
1093 jpcrr.write_word = function(addr, value)
1094 invokesync("memory-write", {toString(addr), toString(value), "2"});
1097 jpcrr.write_dword = function(addr, value)
1098 invokesync("memory-write", {toString(addr), toString(value), "4"});
1101 jpcrr.read_byte = function(addr)
1102 local t = {toString(addr), "1"};
1103 t = invokecall("memory-read", t);
1104 return (t or {})[1];
1107 jpcrr.read_word = function(addr)
1108 local t = {toString(addr), "2"};
1109 t = invokecall("memory-read", t);
1110 return (t or {})[1];
1113 jpcrr.read_dword = function(addr)
1114 local t = {toString(addr), "4"};
1115 t = invokecall("memory-read", t);
1116 return (t or {})[1];
1119 jpcrr.read_byte_signed = function(addr)
1120 local t = {toString(addr), "1"};
1121 t = invokecall("memory-read", t);
1122 return bit.tosigned((t or {})[1], 7);
1125 jpcrr.read_word_signed = function(addr)
1126 local t = {toString(addr), "2"};
1127 t = invokecall("memory-read", t);
1128 return bit.tosigned((t or {})[1], 15);
1131 jpcrr.read_dword_signed = function(addr)
1132 local t = {toString(addr), "4"};
1133 t = invokecall("memory-read", t);
1134 return bit.tosigned((t or {})[1], 31);
1137 jpcrr.invoke = nil;
1138 jpcrr.invoke_synchronous = nil;
1139 jpcrr.call = null
1141 -- Dofile.
1142 dofile = function(_script)
1143 local chunk, err, indication
1144 chunk, err = loadfile(_script);
1145 if not chunk then
1146 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1148 return chunk();
1151 local args2 = args;
1152 args = null;
1153 args = {};
1154 for k, v in pairs(args2) do
1155 if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1156 args[string.sub(k, 3)] = v;
1159 jpcrr_raw = null;
1162 chunk = null;
1163 loaded, err = pcall(function()
1164 chunk, err = loadfile(script);
1165 if not chunk then
1166 error(err);
1168 end);
1169 if not loaded then
1170 print("Kernel: Can't load script " .. script .. ": " .. err);
1171 invoke("luaplugin-terminate");
1172 while true do end
1175 script = null;
1176 indication, err = pcall(chunk);
1177 if not indication then
1178 print("Kernel: Unprotected error in script: " .. err);
1179 invoke("luaplugin-terminate");
1180 while true do end