2 -- Copyright 2009-2010 Ilari Liusvaara
4 -- Licenced under GNU GPL v2.
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
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
24 -- - bit.any(number...)
25 -- Returns 48-bit number that has those bits set that are set in any of its
27 -- - bit.parity(number...)
28 -- Returns 48-bit number that has those bits set that are set in even number
30 -- - bit.any(number...)
31 -- Returns 48-bit number that has those bits set that are set in all of its
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
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_event()
75 -- Waits for event. Returns event type and extra message (if present). Event
76 -- Types are "lock", "stop", "attach" and "message". Note that if you get event
77 -- of type "lock", you are now in frame hold.
78 -- - jpcrr.poll_event()
79 -- Same as wait_event(), but does not wait for event to occur (returns nil if there
81 -- - jpcrr.in_frame_hold()
82 -- Returns true if in frame hold, false otherwise.
83 -- - jpcrr.keypressed(number key)
84 -- Return true if key is pressed, else false.
85 -- - jpcrr.keypressed_edge(number key)
86 -- Return true if key is pressed at input edge, else false.
87 -- - jpcrr.release_vga()
88 -- Allow VGA to exit frame hold mode. Wait for frame hold first.
89 -- - jpcrr.shutdown_emulator()
90 -- Shutdown the entiere emulator immediately (graceful shutdown, PCRunner only).
91 -- - jpcrr.hud.left_gap(number flags, number gap)
92 -- Set left 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.right_gap(number flags, number gap)
95 -- Set right gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
96 -- 1 (2) is set, dump to video dump.
97 -- - jpcrr.hud.top_gap(number flags, number gap)
98 -- Set top gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
99 -- 1 (2) is set, dump to video dump.
100 -- - jpcrr.hud.bottom_gap(number flags, number gap)
101 -- Set bottom gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
102 -- 1 (2) is set, dump to video dump.
103 -- - jpcrr.hud.white_solid_box(number flags, number x, number y, number w, number h)
104 -- Draw with solid opaque box.
105 -- - jpcrr.hud.box(number flags, number x, number y, number w, number h, number linethick,
106 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
107 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
108 -- Draw box with specified size, border line thickness, line color and fill color.
109 -- - jpcrr.hud.circle(number flags, number x, number y, number r, number linethick,
110 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
111 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
112 -- Draw circle with specified size, border line thickness, line color and fill color.
113 -- - jpcrr.hud.bitmap(number flags, number x, number y, string bmap,
114 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
115 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
116 -- Draw bitmap with specified foreground color and background color.
117 -- - jpcrr.hud.bitmap_binary(number flags, number x, number y, string bmap,
118 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
119 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
120 -- Draw binary bitmap with specified foreground color and background color.
121 -- - jpcrr.hud.changen(number flags, number x, number y, string text,
122 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
123 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha,
124 -- boolean multiline)
125 -- Output string using chargen.
126 -- - jpcrr.events.count()
127 -- Return current event count. Nil if no PC.
128 -- - jpcrr.events.current_sequence()
129 -- Return sequence number of next event (event sequence numbers are 0-based). Nil if
130 -- no PC, -1 if at end of movie.
131 -- - jpcrr.events.by_sequence(number seq)
132 -- Return array for specified event. Nil if no PC, empty array if not valid sequence
133 -- number. Otherwise, first element of array is timestamp (numeric), the second is
134 -- event class and rest are the arguments.
135 -- - jpcrr.component_encode(table components)
136 -- Return component encoding for specified components.
137 -- - jpcrr.component_decode(string line)
138 -- Return component decoding for specified line, nil/nil if it doesn't encode
139 -- anything, nil/string if parse error occurs (the error is the second return).
140 -- - jpcrr.save_state(string name)
141 -- Savestate into specified file. Returns name used.
142 -- - jpcrr.save_movie(string name)
143 -- Save movie into specified file. Returns name used.
144 -- - jpcrr.load_state_normal(string name)
145 -- Load specified savestate. Returns name used.
146 -- - jpcrr.load_state_preserve_events(string name)
147 -- Load specified savestate, preserving events. Returns name used.
148 -- - jpcrr.load_state_movie(string name)
149 -- Load specified savestate as movie. Returns name used.
150 -- - jpcrr.assemble()
151 -- Open system settings dialog.
152 -- - jpcrr.change_authors()
153 -- Open change authors dialog.
154 -- - jpcrr.exit = function()
156 -- - jpcrr.ram_dump(string name, boolean binary)
157 -- Dump PC memory to specified file. If binary is true, dump is binary, otherwise
158 -- textual hexadecimal dump.
159 -- - jpcrr.write_byte(number addr, number value)
160 -- Write byte to specified physical address.
161 -- - jpcrr.write_word(number addr, number value)
162 -- Write word to specified physical address (little endian).
163 -- - jpcrr.write_dword(number addr, number value)
164 -- Write dword to specified physical address (little endian).
165 -- - jpcrr.read_byte(number addr)
166 -- Return byte from specified physical address.
167 -- - jpcrr.read_word(number addr)
168 -- Return word from specified physical address (little endian).
169 -- - jpcrr.read_dword(number addr)
170 -- Return dword from specified physical address (little endian).
171 -- - jpcrr.read_byte_signed(number addr)
172 -- Return signed byte from specified physical address.
173 -- - jpcrr.read_word_signed(number addr)
174 -- Return signed word from specified physical address (little endian).
175 -- - jpcrr.read_dword_signed(number addr)
176 -- Return signed dword from specified physical address (little endian).
177 -- - jpcrr.timed_trap(number nsecs)
178 -- Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
179 -- - jpcrr.vretrace_start_trap(boolean is_on)
180 -- Set trap on vretrace start on/off.
181 -- - jpcrr.vretrace_end_trap(boolean is_on)
182 -- Set trap on vretrace end on/off.
183 -- - jpcrr.bios_kbd_trap(boolean is_on)
184 -- Set trap on BIOS kbd on/off.
185 -- - jpcrr.pc_start()
186 -- Start PC execution.
188 -- Stop PC execution.
189 -- - jpcrr.set_pccontrol_pos(number x, number y)
190 -- Set position of PCControl window.
191 -- - jpcrr.set_luaplugin_pos(number x, number y)
192 -- Set position of LuaPlugin window.
193 -- - jpcrr.set_pcmonitor_pos(number x, number y)
194 -- Set position of PCMonitor window.
195 -- - jpcrr.set_pcstartstoptest_pos(number x, number y)
196 -- Set position of PCStartStopTest window.
197 -- - jpcrr.set_virtualkeyboard_pos(number x, number y)
198 -- Set position of VirtualKeyboard window.
199 -- - jpcrr.stringlessthan(String x, String y)
200 -- Return true if x is before y in codepoint lexical order, otherwise false.
201 -- - jpcrr.screenshot(boolean include_hud)
202 -- Take screen shot (Requires monitor). If include_hud is true, include HUD
203 -- (as shown on screen). Note that this should only be called during frame
204 -- hold or results are pretty much undefined.
205 -- - jpcrr.sendevent(string class, string/number...)
206 -- Sends specified event.
207 -- - jpcrr.sendevent_lowbound(number lowbound, string class, string/number...)
208 -- Sends specified event with specified time low bound.
209 -- - jpcrr.register_redraw_function(function)
210 -- This function is called every time screen is redrawn. It is called with
211 -- VGA lock held and that lock is automatically released after call. If this
212 -- function has been registered, no lock events will be generated.
213 -- - jpcrr.register_message_function(function)
214 -- This function is called with message as parameter every time message is
215 -- received. Suppresses message events.
216 -- - jpcrr.register_attach_function(function)
217 -- This function is called every time attach is
218 -- received. Suppresses attach events.
219 -- - jpcrr.register_stop_function(function)
220 -- This function is called every time stop is
221 -- received. Suppresses stop events.
222 -- - jpcrr.register_uiaction_function(function)
223 -- This function is called with widget name as parameter every time
224 -- UI action event is received. Suppresses ui action events.
225 -- - jpcrr.stop_and_execute(function)
226 -- Stop PC execution and call specified function after PC has stopped
227 -- fully. Note that only handler functions receive events until this
229 -- - jpcrr.hostmemory.read()
230 -- Returns contents of host memory.
231 -- - jpcrr.hostmemory.write(string contents)
232 -- Overwrites host memory with specified string.
234 -- Returns table of various status indications (if practicular status is not available, it is nil):
235 -- running: true if PC is running, otherwise false.
236 -- time: Current clock time in nanoseconds.
237 -- resolution_x: Current VGA resolution X component (0 or -1 if no valid signal).
238 -- resolution_y: Current VGA resolution Y component (0 or -1 if no valid signal).
239 -- frame: Frame VGA is on (number of positive edges of retrace signal).
240 -- movie_length: Movie length in nanoseconds.
241 -- movie_rerecords: Rerecord count in last loaded movie.
242 -- movie_headers: Various non-system headers of last loaded movie.
243 -- project_id: Project ID of last loaded movie.
244 -- vga_scrolls: Number of times VGA hardware scrolling has been used.
245 -- vga_retraces_seen: Number of VGA vretrace positive edges seen by software.
246 -- irq0_dispatched: Number of IRQ0s dispatched (all of those may not be delivered).
247 -- irq0_frequency: IRQ0 frequency divider (base frequency is 1193182Hz).
248 -- keyboard_leds_valid: True if keyboard LED data is valid, false otherwise.
249 -- keyboard_num_lock: Status of keyboard num lock.
250 -- keyboard_caps_lock: Status of keyboard num lock.
251 -- keyboard_scroll_lock: Status of keyboard num lock.
252 -- mouse_dx_pending: mouse x movement amount pending in queue.
253 -- mouse_dy_pending: mouse y movement amount pending in queue.
254 -- mouse_dz_pending: mouse z movement amount pending in queue.
255 -- mouse_button_1: Status of mouse button 1.
256 -- mouse_button_2: Status of mouse button 2.
257 -- mouse_button_3: Status of mouse button 3.
258 -- mouse_button_4: Status of mouse button 4.
259 -- mouse_button_5: Status of mouse button 5.
260 -- joystick_ax: Joystick A X-axis hold duration.
261 -- joystick_ay: Joystick A Y-axis hold duration.
262 -- joystick_bx: Joystick B X-axis hold duration.
263 -- joystick_by: Joystick B Y-axis hold duration.
264 -- joystick_aa: Joystick A button A.
265 -- joystick_ab: Joystick A button B.
266 -- joystick_ba: Joystick B button A.
267 -- joystick_bb: Joystick B button B.
269 -- I/O functions have the following conventions. If function returns any real data, the first
270 -- return value returns this data or is nil. Otherwise first return value is true or false.
271 -- If first return value is nil or false, then the second return value gives textual error
272 -- message for failed operation, or is nil if EOF occured before anything was read.
274 -- Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
275 -- success or failure.
277 -- Specifying nil as name of file results random filename being used (it even works with unlink,
278 -- mkdir, rename and read-only access, but doesn't make any sense there).
280 -- Specifying empty filename prompts for file (doesn't work with mkdir, rename nor unlink). Use
281 -- '/<title>' to specify title for prompt dialog.
283 -- Class: BinaryFile:
284 -- Binary file for RO or RW access. Methods are as follows:
286 -- Return name of file.
288 -- Return length of file.
289 -- - set_length(number length)
290 -- Truncate file to specified length
291 -- - read(number offset, number length)
292 -- Read up to length bytes from offset.
293 -- - write(number offset, string content)
294 -- Write content to specified offset.
297 -- Class: BinaryInput:
298 -- Binary file for sequential input. Methods are as follows:
300 -- Return name of file.
302 -- Return BinaryInput that is four to five decoding of this stream.
304 -- Return stream as TextInput.
306 -- Return BinaryInput that is inflate of this stream.
307 -- - read(number bytes)
308 -- Read up to bytes bytes from file.
310 -- Read the entiere file at once.
313 -- Character set for binary files is Latin-1.
315 -- Class: BinaryOutput:
316 -- Binary file for sequential output. Methods are as follows:
318 -- Return name of file.
320 -- Return BinaryOutput that writes four to five encoded output to this stream.
322 -- Return stream as TextOutput.
324 -- Return BinaryOutput that writes deflate output to this stream.
325 -- - write(string content)
326 -- Write string to file.
329 -- Character set for binary files is Latin-1.
333 -- Return name of file.
335 -- Read line from file.
336 -- - read_component()
337 -- Read next componented line into array.
339 -- Line iterator function.
342 -- Character set for text files is UTF-8.
344 -- Class: TextOutput:
346 -- Return name of file.
347 -- - write(string line)
348 -- Write line line to file.
349 -- - write_component(table components)
350 -- Write componented line.
353 -- Character set for text files is UTF-8.
356 -- - member(string name)
357 -- Open substream for member name. The methods are the same as for io.opentextin.
358 -- - member_binary(string name)
359 -- Open binary (four to five) substream for member name. The methods are the same as
360 -- for io.openbinaryin.
362 -- Close the file. Any opened substreams are invalidated.
364 -- Return table listing all members of archive (sorted by name).
366 -- - member(string name)
367 -- Open substream for member name. The methods are the same as for io.opentextout. Note that
368 -- previous member must be closed before next can open.
369 -- - member_binary(string name)
370 -- Open binary (four to five) substream for member name. The methods are the same as
371 -- for io.openbinaryout. Note that previous substream must be closed before next can open.
373 -- Commit the file. No substream may be open. Closes the file.
375 -- Rollback the file. No substream may be open. Closes the file.
377 -- - io.open(string name, string mode) -> BinaryFile
378 -- Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
380 -- - io.open_read(string name) -> BinaryInput
381 -- Open file named @name as binary input stream.
382 -- - io.open_write(string name) -> BinaryOutput
383 -- Open file named @name as binary input stream.
384 -- - io.open_arch_read(string name) -> ArchiveIn
385 -- Open file named @name as input archive.
386 -- - io.open_arch_write(string name) -> ArchiveOut
387 -- Open file named @name as output archive.
388 -- - io.mkdir(string name)
389 -- Create directory name. Returns name created on success, nil on failure.
390 -- - io.unlink(string name)
391 -- Delete file/directory name. Returns name deleted on success, nil on failure.
392 -- - io.rename(string old, string new)
393 -- Rename file old -> new. Returns old, new on success, nil on failure.
394 -- - io.transform.text()
395 -- Returns function that calls text() method of its parameter.
396 -- - io.transform.four_to_five()
397 -- Returns function that calls four_to_five() method of its parameter.
398 -- - io.transform.deflate()
399 -- Returns function that calls deflate() method of its parameter.
400 -- - io.transform.inflate()
401 -- Returns function that calls inflate() method of its parameter.
402 -- - io.dotransform(object obj, function...)
403 -- Call specified functions on specified object. If any function fails (first argument nil
404 -- or false), call close method on preceeding object. Otherwise call specified functions
405 -- chained left to right and return the result.
406 -- - io.dotransform2(object obj, string err, function...)
407 -- Similar to dotransform except if obj is nil or false, returns obj, err.
408 -- - jpcrr.random.nextBoolean()
409 -- Returns random boolean.
410 -- - jpcrr.random.nextBytes(number bytes)
411 -- Returns random string of bytes [0,255], bytes chars in length.
412 -- - jpcrr.random.nextDouble()
413 -- Returns random double [0,1)
414 -- - jpcrr.random.nextFloat()
415 -- Returns random float [0,1)
416 -- - jpcrr.random.nextGaussian()
417 -- Returns random number according to gaussian distribution (expectation 0, stddev 1).
418 -- - jpcrr.random.nextInt([number bound])
419 -- Return random integer [0,bound). If no bound is specified, random 32-bit number is returned.
420 -- - jpcrr.random.nextLong()
421 -- Return random long.
424 local stopping = false;
425 local mesage_function = nil;
426 local lock_function = nil;
427 local uiaction_function = nil;
428 local stop_function = nil;
429 local attach_function = nil;
430 local _print_console_msg = print_console_msg;
432 local handle, err, chunk, indication, k, v;
434 local loadmod = loadmodule;
437 local export_module_in = function(tab, modname, prefix)
438 local fun = loadmod(modname);
440 _print_console_msg("Extension library " .. modname .. " not found");
443 for k, v in pairs(fun) do
444 tab[(prefix or "") .. k] = v;
452 jpcrr.memorysearch = {};
453 jpcrr.hostmemory = {};
459 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
460 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
461 export_module_in(jpcrr, "org.jpc.luaextensions.Status");
462 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
463 export_module_in(jpcrr.events, "org.jpc.luaextensions.Events");
464 export_module_in(jpcrr.window, "org.jpc.luaextensions.Window");
465 export_module_in(bit, "org.jpc.luaextensions.Bitops");
466 export_module_in(jpcrr.memorysearch, "org.jpc.luaextensions.MemorySearch");
467 export_module_in(HUD, "org.jpc.luaextensions.HUD");
468 export_module_in(jpcrr.hostmemory, "org.jpc.luaextensions.HostMemory");
469 export_module_in(jpcrr.random, "org.jpc.luaextensions.Random");
475 -- Few misc functions.
476 assert = function(val, err)
477 if (not val) and err then
483 modulus_split = function(number, ...)
484 local dividers = {...};
488 for k, v in ipairs(dividers) do
490 table.insert(results, (number - rem) / v);
494 table.insert(results, number);
495 return unpack(results);
498 jpcrr.register_redraw_function = function(f)
499 if f and type(f) ~= "function" then
500 error("Incorrect type of argument to register_redraw_function");
505 jpcrr.register_message_function = function(f)
506 if f and type(f) ~= "function" then
507 error("Incorrect type of argument to register_message_function");
509 message_function = f;
512 jpcrr.register_stop_function = function(f)
513 if f and type(f) ~= "function" then
514 error("Incorrect type of argument to register_stop_function");
519 jpcrr.register_attach_function = function(f)
520 if f and type(f) ~= "function" then
521 error("Incorrect type of argument to register_attach_function");
526 jpcrr.register_uiaction_function = function(f)
527 if f and type(f) ~= "function" then
528 error("Incorrect type of argument to register_uiaction_function");
530 uiaction_function = f;
535 local getmtable = getmetatable;
536 local toString = tostring;
537 local inject_binary_file;
538 local inject_binary_input;
539 local inject_binary_output;
540 local inject_text_input;
541 local inject_text_output;
542 local inject_archive_input;
543 local inject_archive_output;
545 -- Class member injectors.
546 inject_binary_file = function(obj, name)
548 getmtable(obj).name = function(obj)
551 getmtable(obj).__index = function(tab, name)
552 local x = getmtable(obj)[name];
556 error("Invalid method " .. name .. " for BinaryFile");
561 inject_binary_input = function(obj, underlying, name)
563 local old_four_to_five = getmtable(obj).four_to_five;
564 local old_inflate = getmtable(obj).inflate;
565 local old_text = getmtable(obj).text;
566 local old_read = getmtable(obj).read;
567 local old_close = getmtable(obj).close;
568 local underlying_object = underlying;
570 getmtable(obj).name = function(obj)
573 getmtable(obj).four_to_five = function(obj)
575 res, err = old_four_to_five(obj);
579 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
581 getmtable(obj).inflate = function(obj)
583 res, err = old_inflate(obj);
587 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
589 getmtable(obj).text = function(obj)
591 res, err = old_text(obj);
595 return inject_text_input(res, obj, "text<" .. _name .. ">");
597 getmtable(obj).read = function(obj, toread)
599 return old_read(obj, toread);
604 ret, err = old_read(obj, 16384);
615 getmtable(obj).close = function(obj)
616 local ret, err, ret2, err2;
617 ret, err = old_close(obj);
618 if underlying_object then ret2, err2 = underlying_object:close(); end
619 if ret and not ret2 then
625 getmtable(obj).__index = function(tab, name)
626 local x = getmtable(obj)[name];
630 error("Invalid method " .. name .. " for BinaryInput");
635 inject_binary_output = function(obj, underlying, name)
637 local old_four_to_five = getmtable(obj).four_to_five;
638 local old_deflate = getmtable(obj).deflate;
639 local old_text = getmtable(obj).text;
640 local old_close = getmtable(obj).close;
641 local underlying_object = underlying;
643 getmtable(obj).name = function(obj)
646 getmtable(obj).four_to_five = function(obj)
648 res, err = old_four_to_five(obj);
652 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
654 getmtable(obj).deflate = function(obj)
656 res, err = old_deflate(obj);
660 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
662 getmtable(obj).text = function(obj)
664 res, err = old_text(obj);
668 return inject_text_output(res, obj, "text<" .. _name .. ">");
670 getmtable(obj).close = function(obj)
671 local ret, err, ret2, err2;
672 ret, err = old_close(obj);
673 if underlying_object then ret2, err2 = underlying_object:close(); end
674 if ret and not ret2 then
680 getmtable(obj).__index = function(tab, name)
681 local x = getmtable(obj)[name];
685 error("Invalid method " .. name .. " for BinaryOutput");
690 inject_text_input = function(obj, underlying, name)
692 local old_close = getmtable(obj).close;
693 local underlying_object = underlying;
695 getmtable(obj).lines = function(obj)
696 return function(state, prevline)
700 getmtable(obj).name = function(obj)
703 getmtable(obj).close = function(obj)
704 local ret, err, ret2, err2;
705 ret, err = old_close(obj);
706 if underlying_object then ret2, err2 = underlying_object:close(); end
707 if ret and not ret2 then
713 getmtable(obj).__index = function(tab, name)
714 local x = getmtable(obj)[name];
718 error("Invalid method " .. name .. " for TextInput");
723 inject_text_output = function(obj, underlying, name)
725 local old_close = getmtable(obj).close;
726 local underlying_object = underlying;
728 getmtable(obj).name = function(obj)
731 getmtable(obj).close = function(obj)
732 local ret, err, ret2, err2;
733 ret, err = old_close(obj);
734 if underlying_object then ret2, err2 = underlying_object:close(); end
735 if ret and underlying_object then
741 getmtable(obj).__index = function(tab, name)
742 local x = getmtable(obj)[name];
746 error("Invalid method " .. name .. " for TextOutput");
751 inject_archive_input = function(obj, name)
753 local old_member = getmtable(obj).member;
754 local old_member_list = getmtable(obj).member_list;
755 getmtable(obj).member = function(obj, member)
757 res, err = old_member(obj, member);
761 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
763 getmtable(obj).name = function(obj)
766 getmtable(obj).member_list = function(obj)
767 local tab = old_member_list(obj);
768 if tab then table.sort(tab, jpcrr.stringlessthan); end
771 getmtable(obj).__index = function(tab, name)
772 local x = getmtable(obj)[name];
776 error("Invalid method " .. name .. " for ArchiveInput");
781 inject_archive_output = function(obj, name)
783 local old_member = getmtable(obj).member;
784 getmtable(obj).member = function(obj, member)
786 res, err = old_member(obj, member);
790 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
792 getmtable(obj).name = function(obj)
795 getmtable(obj).__index = function(tab, name)
796 local x = getmtable(obj)[name];
800 error("Invalid method " .. name .. " for ArchiveOutput");
806 -- Redefined routines.
808 local rprint = print_console_msg;
809 print_console_msg = nil;
810 print = function(...)
816 x = x .. "\t" .. toString(y[i]);
823 print_console_msg = nil;
829 local stringfind = string.find;
830 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
831 local selectname = loadmod("org.jpc.luaextensions.BaseFSOps").opensave_dialog;
832 local path = args["luapath"] or ".";
833 local toresourcename = function(resname, save, text)
835 return randname(path .. "/", "luatemp-");
838 if resname == "" and text then
840 a, b = selectname(save, text);
844 if stringfind(resname, "^/") then
846 error("Bad resource name (case 2): " .. resname);
849 a, b = selectname(save, string.sub(resname, 2));
853 if not stringfind(resname, "[%d%l%u_%-]") then
854 error("Bad resource name (case 1): " .. resname);
856 if stringfind(resname, "%.%.") then
857 error("Bad resource name (case 3): " .. resname);
859 if stringfind(resname, "\\") then
860 error("Bad resource name (case 4): " .. resname);
863 return resname, path .. "/" .. resname;
868 local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
869 local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
870 local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
871 local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
872 local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
874 local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
875 local mkdir = baseFS.mkdir;
876 local unlink = baseFS.unlink;
877 local rename = baseFS.rename;
879 local getmtable = getmetatable;
881 loadfile = function(_script)
882 local file, file2, err, content;
884 x, y = toresourcename(_script, false, "Select script to load");
885 if not x then return x, y; end
886 file, err = openbinin(y, "r");
888 return nil, "Can't open " .. _script .. ": " .. err;
890 file2, err = file:text();
892 return nil, "Can't transform " .. _script .. ": " .. err;
897 content = content .. line .. "\n";
902 return loadstring(content, _script);
905 io.open = function(name, mode)
910 _name, y = toresourcename(name, false, "Select file to read");
912 _name, y = toresourcename(name, true, "Select file to write");
914 if not _name then return _name, y; end
915 res, err = openbinary(y, mode);
919 return inject_binary_file(res, _name);
922 io.open_arch_read = function(name)
926 _name, y = toresourcename(name, false, "Select archive to read");
927 if not _name then return _name, y; end
928 res, err = openarchin(y);
932 return inject_archive_input(res, _name);
935 io.open_arch_write = function(name)
939 _name, y = toresourcename(name, true, "Select archive to write");
940 if not _name then return _name, y; end
941 res, err = openarchout(y);
945 return inject_archive_output(res, _name);
948 io.open_read = function(name)
952 _name, y = toresourcename(name, false, "Select file to read");
953 if not _name then return _name, y; end
954 res, err = openbinin(y);
958 return inject_binary_input(res, nil, _name);
961 io.open_write = function(name)
965 _name, y = toresourcename(name, true, "Select file to write");
966 if not _name then return _name, y; end
967 res, err = openbinout(y);
971 return inject_binary_output(res, nil, _name);
974 io.mkdir = function(name)
976 _name, y = toresourcename(name);
984 io.unlink = function(name)
986 _name, y = toresourcename(name);
994 io.rename = function(name1, name2)
997 _name, y = toresourcename(name1);
998 _name2, y2 = toresourcename(name2);
999 if rename(y, y2) then
1000 return _name, _name2;
1008 io.transform.text = function()
1009 return function(obj)
1014 io.transform.four_to_five = function()
1015 return function(obj)
1016 return obj:four_to_five();
1020 io.transform.inflate = function()
1021 return function(obj)
1022 return obj:inflate();
1026 io.transform.deflate = function()
1027 return function(obj)
1028 return obj:deflate();
1032 io.dotransform = function(obj, ...)
1036 for k, v in ipairs(todo) do
1047 io.dotransform2 = function(obj, err, ...)
1051 return io.dotransform(obj, err, ...);
1056 -- Various stuff built on top of ECI.
1057 local invoke = jpcrr.invoke;
1058 local invokecall = jpcrr.call;
1059 local invokesync = jpcrr.invoke_synchronous;
1061 jpcrr.sendevent = function(...)
1062 local arguments = {...};
1064 for k, v in ipairs(arguments) do
1065 arguments[k] = toString(v);
1067 invokesync("sendevent", arguments);
1070 jpcrr.sendevent_lowbound = function(...)
1071 local arguments = {...};
1073 for k, v in ipairs(arguments) do
1074 arguments[k] = toString(v);
1076 invokesync("sendevent-lowbound", arguments);
1079 jpcrr.save_state = function(name)
1080 local _name, _fname;
1081 _name, _fname = toresourcename(name, true, "File to savestate to");
1082 invokesync("state-save", {_fname});
1086 jpcrr.save_movie = function(name)
1087 local _name, _fname;
1088 _name, _fname = toresourcename(name, true, "File to save movie to");
1089 invokesync("movie-save", {_fname});
1093 jpcrr.load_state_normal = function(name)
1094 local _name, _fname;
1095 _name, _fname = toresourcename(name, false, "File to loadstate from");
1096 invokesync("state-load", {_fname});
1100 jpcrr.load_state_preserve_events = function(name)
1101 local _name, _fname;
1102 _name, _fname = toresourcename(name, false, "File to loadstate (preserve events) from");
1103 invokesync("state-load-noevents", {_fname});
1107 jpcrr.load_state_movie = function(name)
1108 local _name, _fname;
1109 _name, _fname = toresourcename(name, false, "File to load movie from");
1110 invokesync("movie-load", {_fname});
1114 jpcrr.assemble = function()
1115 invokesync("pc-assemble");
1118 jpcrr.change_authors = function()
1119 invokesync("change-authors");
1122 jpcrr.ram_dump = function(name, binary)
1123 local _name, _fname;
1124 _name, _fname = toresourcename(name, true, "Select file to ramdump to");
1126 invokesync("ram-dump-binary", {_fname});
1128 invokesync("ram-dump-text", {_fname});
1133 local poll_event = jpcrr.poll_event;
1134 local _print = print;
1135 local _unlock = jpcrr.release_vga;
1136 jpcrr.poll_event = function()
1138 local failed = false;
1140 a, b = poll_event();
1144 if a and a == "message" and message_function then
1145 a, b = pcall(message_function, b);
1147 _print("Error running message callback: " .. b);
1151 if a and a == "uiaction" and uiaction_function then
1152 a, b = pcall(uiaction_function, b);
1154 _print("Error running uiaction callback: " .. b);
1158 if a and a == "stop" and stop_function then
1159 a, b = pcall(stop_function);
1161 _print("Error running stop callback: " .. b);
1165 if a and a == "attach" and attach_function then
1166 a, b = pcall(attach_function);
1168 _print("Error running attach callback: " .. b);
1172 if a and a == "lock" and lock_function then
1173 a, b = pcall(lock_function);
1176 _print("Error running redraw callback: " .. b);
1183 if a and a == "lock" and stopping then
1192 local wait_event = jpcrr.wait_event;
1193 local _print = print;
1194 local _unlock = jpcrr.release_vga;
1195 jpcrr.wait_event = function()
1198 a, b = wait_event();
1199 if a and a == "message" and message_function then
1200 a, b = pcall(message_function, b);
1202 _print("Error running message callback: " .. b);
1206 if a and a == "uiaction" and uiaction_function then
1207 a, b = pcall(uiaction_function, b);
1209 _print("Error running uiaction callback: " .. b);
1213 if a and a == "stop" and stop_function then
1214 a, b = pcall(stop_function);
1216 _print("Error running stop callback: " .. b);
1220 if a and a == "attach" and attach_function then
1221 a, b = pcall(attach_function);
1223 _print("Error running attach callback: " .. b);
1227 if a and a == "lock" and lock_function then
1228 a, b = pcall(lock_function);
1231 _print("Error running redraw callback: " .. b);
1243 jpcrr.hud.left_gap = function(f, g)
1244 HUD("left_gap", f, g);
1247 jpcrr.hud.right_gap = function(f, g)
1248 HUD("right_gap", f, g);
1251 jpcrr.hud.top_gap = function(f, g)
1252 HUD("top_gap", f, g);
1255 jpcrr.hud.bottom_gap = function(f, g)
1256 HUD("bottom_gap", f, g);
1259 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
1260 HUD("hud_white_solid_box", f, x, y, w, h);
1263 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
1269 HUD("box", f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa);
1272 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1278 HUD("circle", f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1281 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1287 HUD("bitmap", f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1290 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1296 HUD("bitmap_binary", f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1299 jpcrr.hud.chargen = function(f, x, y, text, multiline, lr, lg, lb, la, fr, fg, fb, fa)
1305 HUD("vga_chargen", f, x, y, text, lr, lg, lb, la, fr, fg, fb, fa, multiline)
1308 jpcrr.shutdown_emulator = function()
1309 invokesync("shutdown-emulator", {});
1312 jpcrr.set_pccontrol_pos = function(x, y)
1313 invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
1316 jpcrr.set_luaplugin_pos = function(x, y)
1317 invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
1320 jpcrr.set_pcmonitor_pos = function(x, y)
1321 invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
1324 jpcrr.set_pcstartstoptest_pos = function(x, y)
1325 invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
1328 jpcrr.set_virtualkeyboard_pos = function(x, y)
1329 invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
1332 jpcrr.exit = function()
1333 invokesync("luaplugin-terminate");
1336 jpcrr.pc_start = function()
1340 jpcrr.pc_stop = function()
1341 invokesync("pc-stop");
1344 jpcrr.screenshot = function(include_hud)
1346 invoke("screenshot-renderbuffer");
1348 invoke("screenshot-vgabuffer");
1352 jpcrr.bios_kbd_trap = function(is_on)
1354 invokesync("trap-bios-kbd-on");
1356 invokesync("trap-bios-kbd-off");
1360 jpcrr.vretrace_start_trap = function(is_on)
1362 invokesync("trap-vretrace-start-on");
1364 invokesync("trap-vretrace-start-off");
1368 jpcrr.vretrace_end_trap = function(is_on)
1370 invokesync("trap-vretrace-end-on");
1372 invokesync("trap-vretrace-end-off");
1376 jpcrr.timed_trap = function(nsecs)
1378 invokesync("trap-timed", {toString(nsecs)});
1380 invokesync("trap-timed-disable");
1384 jpcrr.write_byte = function(addr, value)
1385 invokesync("memory-write", {toString(addr), toString(value), "1"});
1388 jpcrr.write_word = function(addr, value)
1389 invokesync("memory-write", {toString(addr), toString(value), "2"});
1392 jpcrr.write_dword = function(addr, value)
1393 invokesync("memory-write", {toString(addr), toString(value), "4"});
1396 jpcrr.read_byte = function(addr)
1397 local t = {toString(addr), "1"};
1398 t = invokecall("memory-read", t);
1399 return (t or {})[1];
1402 jpcrr.read_word = function(addr)
1403 local t = {toString(addr), "2"};
1404 t = invokecall("memory-read", t);
1405 return (t or {})[1];
1408 jpcrr.read_dword = function(addr)
1409 local t = {toString(addr), "4"};
1410 t = invokecall("memory-read", t);
1411 return (t or {})[1];
1414 jpcrr.read_byte_signed = function(addr)
1415 local t = {toString(addr), "1"};
1416 t = invokecall("memory-read", t);
1417 return bit.tosigned((t or {})[1], 7);
1420 jpcrr.read_word_signed = function(addr)
1421 local t = {toString(addr), "2"};
1422 t = invokecall("memory-read", t);
1423 return bit.tosigned((t or {})[1], 15);
1426 jpcrr.read_dword_signed = function(addr)
1427 local t = {toString(addr), "4"};
1428 t = invokecall("memory-read", t);
1429 return bit.tosigned((t or {})[1], 31);
1432 local e_wait_event = jpcrr.wait_event;
1433 local running = jpcrr.pc_running;
1434 local stop_and_execute_in_progress = false;
1435 jpcrr.stop_and_execute = function(f)
1438 if stop_and_execute_in_progress then
1441 if not running() then
1444 error("Error in after stop callback: " .. b);
1450 stop_and_execute_in_progress = true;
1451 a, b = e_wait_event();
1452 stop_and_execute_in_progress = false;
1453 if a and a == "lock" then
1458 elseif a and (a == "stop" or a == "attach") then
1465 error("Error in after stop callback: " .. b);
1470 -- Various legacy functions.
1471 local legacy_warning = {};
1472 local warn_legacy = function(name)
1473 if not legacy_warning[name] then
1474 _print("Warning: " .. name .. " is deprecated.");
1475 legacy_warning[name] = true;
1479 jpcrr.pc_running = function()
1480 warn_legacy("jpcrr.pc_running");
1481 local status = jpcrr.status();
1482 return (status ~= nil) and status.running;
1485 jpcrr.clock_time = function()
1486 warn_legacy("jpcrr.clock_time");
1487 local status = jpcrr.status();
1494 jpcrr.vga_edge_count = function()
1495 warn_legacy("jpcrr.vga_edge_count");
1496 local status = jpcrr.status();
1500 return status.vga_retraces_seen or 0;
1503 jpcrr.pc_connected = function()
1504 warn_legacy("jpcrr.pc_connected");
1505 local status = jpcrr.status();
1506 return status ~= nil;
1509 jpcrr.vga_scroll_count = function()
1510 warn_legacy("jpcrr.vga_scroll_count");
1511 local status = jpcrr.status();
1515 return status.vga_scroll_count or 0;
1518 jpcrr.vga_resolution = function()
1519 warn_legacy("jpcrr.vga_scroll_count");
1520 local status = jpcrr.status();
1524 return status.resolution_x, status.resolution_y;
1527 jpcrr.get_irq0_info = function()
1528 warn_legacy("jpcrr.get_irq0_info");
1529 local status = jpcrr.status();
1533 return status.irq0_dispatched, status.irq0_frequency;
1536 jpcrr.frame_number = function()
1537 warn_legacy("jpcrr.frame_number");
1538 local status = jpcrr.status();
1542 return status.frame;
1545 jpcrr.movie_rerecords = function()
1546 warn_legacy("jpcrr.movie_rerecords");
1547 local status = jpcrr.status();
1551 return status.movie_rerecords;
1554 jpcrr.movie_length = function()
1555 warn_legacy("jpcrr.movie_length");
1556 local status = jpcrr.status();
1560 return status.movie_length;
1563 jpcrr.movie_headers = function()
1564 warn_legacy("jpcrr.movie_headers");
1565 local status = jpcrr.status();
1569 return status.movie_headers;
1572 jpcrr.project_id = function()
1573 warn_legacy("jpcrr.project_id");
1574 local status = jpcrr.status();
1578 return status.project_id;
1581 jpcrr.keyboard_leds = function()
1582 warn_legacy("jpcrr.keyboard_leds");
1583 local status = jpcrr.status();
1584 if not status or status.keyboard_leds_valid == nil then
1587 if not status.keyboard_leds_valid then
1590 return status.keyboard_num_lock, status.keyboard_caps_lock, status.keyboard_scroll_lock;
1593 jpcrr.joystick_state = function()
1594 warn_legacy("jpcrr.joystick_state");
1595 local status = jpcrr.status();
1596 if not status or status.joystick_ax == nil then
1599 return status.joystick_ax, status.joystick_ay, status.joystick_bx, status.joystick_by,
1600 status.joystick_aa, status.joystick_ab, status.joystick_ba, status.joystick_bb;
1603 jpcrr.mouse_state = function()
1604 warn_legacy("jpcrr.mouse_state");
1605 local status = jpcrr.status();
1609 return status.mouse_dx_pending, status.mouse_dy_pending, status.mouse_dz_pending,
1610 status.mouse_button_1, status.mouse_button_2, status.mouse_button_3, status.mouse_button_4,
1611 status.mouse_button_5;
1615 jpcrr.invoke_synchronous = nil;
1619 dofile = function(_script)
1620 local chunk, err, indication
1621 chunk, err = loadfile(_script);
1623 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1631 for k, v in pairs(args2) do
1632 if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1633 args[string.sub(k, 3)] = v;
1640 loaded, err = pcall(function()
1641 chunk, err = loadfile(script);
1647 print("Kernel: Can't load script " .. script .. ": " .. err);
1648 invoke("luaplugin-terminate");
1653 indication, err = pcall(chunk);
1654 if not indication then
1655 print("Kernel: Unprotected error in script: " .. err);
1656 invoke("luaplugin-terminate");