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.pc_running()
82 -- Returns true if PC is running.
83 -- - jpcrr.clock_time()
84 -- Returns current time or nil if no PC.
85 -- - jpcrr.vga_edge_count()
86 -- Returns how many times VGA vretrace signal has been seen rising.
87 -- - jpcrr.vga_scroll_count()
88 -- Returns how many times VGA has scrolled.
89 -- - jpcrr.pc_connected()
90 -- Returns true if PC is connected.
91 -- - jpcrr.in_frame_hold()
92 -- Returns true if in frame hold, false otherwise.
93 -- - jpcrr.keypressed(number key)
94 -- Return true if key is pressed, else false.
95 -- - jpcrr.keypressed_edge(number key)
96 -- Return true if key is pressed at input edge, else false.
97 -- - jpcrr.release_vga()
98 -- Allow VGA to exit frame hold mode. Wait for frame hold first.
99 -- - jpcrr.vga_resolution()
100 -- Return VGA x and y resolutions. -1x-1 or 0x0 is returned if no valid resolution.
101 -- Should only be called during frame hold.
102 -- - jpcrr.frame_number()
103 -- Return current VGA frame number or nil if no PC present.
104 -- - jpcrr.shutdown_emulator()
105 -- Shutdown the entiere emulator immediately (graceful shutdown, PCRunner only).
106 -- - jpcrr.hud.left_gap(number flags, number gap)
107 -- Set left gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
108 -- 1 (2) is set, dump to video dump.
109 -- - jpcrr.hud.right_gap(number flags, number gap)
110 -- Set right gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
111 -- 1 (2) is set, dump to video dump.
112 -- - jpcrr.hud.top_gap(number flags, number gap)
113 -- Set top gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
114 -- 1 (2) is set, dump to video dump.
115 -- - jpcrr.hud.bottom_gap(number flags, number gap)
116 -- Set bottom gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
117 -- 1 (2) is set, dump to video dump.
118 -- - jpcrr.hud.white_solid_box(number flags, number x, number y, number w, number h)
119 -- Draw with solid opaque box.
120 -- - jpcrr.hud.box(number flags, number x, number y, number w, number h, number linethick,
121 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
122 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
123 -- Draw box with specified size, border line thickness, line color and fill color.
124 -- - jpcrr.hud.circle(number flags, number x, number y, number r, number linethick,
125 -- number lineRed, number lineGreen, number lineBlue, number lineAlpha,
126 -- number fillRed, number fillGreen, number fillBlue, number fillAlpha)
127 -- Draw circle with specified size, border line thickness, line color and fill color.
128 -- - jpcrr.hud.bitmap(number flags, number x, number y, string bmap,
129 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
130 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
131 -- Draw bitmap with specified foreground color and background color.
132 -- - jpcrr.hud.bitmap_binary(number flags, number x, number y, string bmap,
133 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
134 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha)
135 -- Draw binary bitmap with specified foreground color and background color.
136 -- - jpcrr.hud.changen(number flags, number x, number y, string text,
137 -- number fgRed, number fgGreen, number fgBlue, number fgAlpha,
138 -- number bgRed, number bgGreen, number bgBlue, number bgAlpha,
139 -- boolean multiline)
140 -- Output string using chargen.
141 -- - jpcrr.events.count()
142 -- Return current event count. Nil if no PC.
143 -- - jpcrr.events.current_sequence()
144 -- Return sequence number of next event (event sequence numbers are 0-based). Nil if
145 -- no PC, -1 if at end of movie.
146 -- - jpcrr.events.by_sequence(number seq)
147 -- Return array for specified event. Nil if no PC, empty array if not valid sequence
148 -- number. Otherwise, first element of array is timestamp (numeric), the second is
149 -- event class and rest are the arguments.
150 -- - jpcrr.joystick_state()
151 -- Returns nil if no joystick. Otherwise returns hold times for all four axis (numeric)
152 -- followed by button states (boolean).
153 -- - jpcrr.keyboard_leds()
154 -- Returns nil if no keyboard, false if LED status is unknown. Otherwise returns three
155 -- booleans, first being state of num lock, second being state of caps lock and third
156 -- being state of scroll lock.
157 -- - jpcrr.mouse_state()
158 -- Returns nil if no mouse. Otherwise returns X, Y and Z axis pending motions (numeric)
159 -- followed by button states (5 booleans).
160 -- - jpcrr.component_encode(table components)
161 -- Return component encoding for specified components.
162 -- - jpcrr.component_decode(string line)
163 -- Return component decoding for specified line, nil/nil if it doesn't encode
164 -- anything, nil/string if parse error occurs (the error is the second return).
165 -- - jpcrr.save_state(string name)
166 -- Savestate into specified file. Returns name used.
167 -- - jpcrr.save_movie(string name)
168 -- Save movie into specified file. Returns name used.
169 -- - jpcrr.load_state_normal(string name)
170 -- Load specified savestate. Returns name used.
171 -- - jpcrr.load_state_preserve_events(string name)
172 -- Load specified savestate, preserving events. Returns name used.
173 -- - jpcrr.load_state_movie(string name)
174 -- Load specified savestate as movie. Returns name used.
175 -- - jpcrr.assemble()
176 -- Open system settings dialog.
177 -- - jpcrr.change_authors()
178 -- Open change authors dialog.
179 -- - jpcrr.exit = function()
181 -- - jpcrr.ram_dump(string name, boolean binary)
182 -- Dump PC memory to specified file. If binary is true, dump is binary, otherwise
183 -- textual hexadecimal dump.
184 -- - jpcrr.write_byte(number addr, number value)
185 -- Write byte to specified physical address.
186 -- - jpcrr.write_word(number addr, number value)
187 -- Write word to specified physical address (little endian).
188 -- - jpcrr.write_dword(number addr, number value)
189 -- Write dword to specified physical address (little endian).
190 -- - jpcrr.read_byte(number addr)
191 -- Return byte from specified physical address.
192 -- - jpcrr.read_word(number addr)
193 -- Return word from specified physical address (little endian).
194 -- - jpcrr.read_dword(number addr)
195 -- Return dword from specified physical address (little endian).
196 -- - jpcrr.read_byte_signed(number addr)
197 -- Return signed byte from specified physical address.
198 -- - jpcrr.read_word_signed(number addr)
199 -- Return signed word from specified physical address (little endian).
200 -- - jpcrr.read_dword_signed(number addr)
201 -- Return signed dword from specified physical address (little endian).
202 -- - jpcrr.timed_trap(number nsecs)
203 -- Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
204 -- - jpcrr.vretrace_start_trap(boolean is_on)
205 -- Set trap on vretrace start on/off.
206 -- - jpcrr.vretrace_end_trap(boolean is_on)
207 -- Set trap on vretrace end on/off.
208 -- - jpcrr.bios_kbd_trap(boolean is_on)
209 -- Set trap on BIOS kbd on/off.
210 -- - jpcrr.pc_start()
211 -- Start PC execution.
213 -- Stop PC execution.
214 -- - jpcrr.set_pccontrol_pos(number x, number y)
215 -- Set position of PCControl window.
216 -- - jpcrr.set_luaplugin_pos(number x, number y)
217 -- Set position of LuaPlugin window.
218 -- - jpcrr.set_pcmonitor_pos(number x, number y)
219 -- Set position of PCMonitor window.
220 -- - jpcrr.set_pcstartstoptest_pos(number x, number y)
221 -- Set position of PCStartStopTest window.
222 -- - jpcrr.set_virtualkeyboard_pos(number x, number y)
223 -- Set position of VirtualKeyboard window.
224 -- - jpcrr.stringlessthan(String x, String y)
225 -- Return true if x is before y in codepoint lexical order, otherwise false.
226 -- - jpcrr.screenshot(boolean include_hud)
227 -- Take screen shot (Requires monitor). If include_hud is true, include HUD
228 -- (as shown on screen). Note that this should only be called during frame
229 -- hold or results are pretty much undefined.
230 -- - jpcrr.sendevent(string class, string/number...)
231 -- Sends specified event.
232 -- - jpcrr.sendevent_lowbound(number lowbound, string class, string/number...)
233 -- Sends specified event with specified time low bound.
234 -- - jpcrr.movie_rerecords()
235 -- Return number of rerecords (nil if no movie loaded).
236 -- - jpcrr.movie_length()
237 -- Return length of movie in ns (nil if no movie loaded).
238 -- - jpcrr.movie_headers()
239 -- Return headers of movie as array of arrays (nil if no movie loaded).
240 -- - jpcrr.register_redraw_function(function)
241 -- This function is called every time screen is redrawn. It is called with
242 -- VGA lock held and that lock is automatically released after call. If this
243 -- function has been registered, no lock events will be generated.
244 -- - jpcrr.register_message_function(function)
245 -- This function is called with message as parameter every time message is
246 -- received. Suppresses message events.
247 -- - jpcrr.register_attach_function(function)
248 -- This function is called every time attach is
249 -- received. Suppresses attach events.
250 -- - jpcrr.register_stop_function(function)
251 -- This function is called every time stop is
252 -- received. Suppresses stop events.
253 -- - jpcrr.register_uiaction_function(function)
254 -- This function is called with widget name as parameter every time
255 -- UI action event is received. Suppresses ui action events.
256 -- - jpcrr.stop_and_execute(function)
257 -- Stop PC execution and call specified function after PC has stopped
258 -- fully. Note that only handler functions receive events until this
260 -- - jpcrr.hostmemory.read()
261 -- Returns contents of host memory.
262 -- - jpcrr.hostmemory.write(string contents)
263 -- Overwrites host memory with specified string.
264 -- - jpcrr.project_id()
265 -- Get the project ID (nil if no movie).
267 -- I/O functions have the following conventions. If function returns any real data, the first
268 -- return value returns this data or is nil. Otherwise first return value is true or false.
269 -- If first return value is nil or false, then the second return value gives textual error
270 -- message for failed operation, or is nil if EOF occured before anything was read.
272 -- Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
273 -- success or failure.
275 -- Specifying nil as name of file results random filename being used (it even works with unlink,
276 -- mkdir, rename and read-only access, but doesn't make any sense there).
278 -- Specifying empty filename prompts for file (doesn't work with mkdir, rename nor unlink). Use
279 -- '/<title>' to specify title for prompt dialog.
281 -- Class: BinaryFile:
282 -- Binary file for RO or RW access. Methods are as follows:
284 -- Return name of file.
286 -- Return length of file.
287 -- - set_length(number length)
288 -- Truncate file to specified length
289 -- - read(number offset, number length)
290 -- Read up to length bytes from offset.
291 -- - write(number offset, string content)
292 -- Write content to specified offset.
295 -- Class: BinaryInput:
296 -- Binary file for sequential input. Methods are as follows:
298 -- Return name of file.
300 -- Return BinaryInput that is four to five decoding of this stream.
302 -- Return stream as TextInput.
304 -- Return BinaryInput that is inflate of this stream.
305 -- - read(number bytes)
306 -- Read up to bytes bytes from file.
308 -- Read the entiere file at once.
311 -- Character set for binary files is Latin-1.
313 -- Class: BinaryOutput:
314 -- Binary file for sequential output. Methods are as follows:
316 -- Return name of file.
318 -- Return BinaryOutput that writes four to five encoded output to this stream.
320 -- Return stream as TextOutput.
322 -- Return BinaryOutput that writes deflate output to this stream.
323 -- - write(string content)
324 -- Write string to file.
327 -- Character set for binary files is Latin-1.
331 -- Return name of file.
333 -- Read line from file.
334 -- - read_component()
335 -- Read next componented line into array.
337 -- Line iterator function.
340 -- Character set for text files is UTF-8.
342 -- Class: TextOutput:
344 -- Return name of file.
345 -- - write(string line)
346 -- Write line line to file.
347 -- - write_component(table components)
348 -- Write componented line.
351 -- Character set for text files is UTF-8.
354 -- - member(string name)
355 -- Open substream for member name. The methods are the same as for io.opentextin.
356 -- - member_binary(string name)
357 -- Open binary (four to five) substream for member name. The methods are the same as
358 -- for io.openbinaryin.
360 -- Close the file. Any opened substreams are invalidated.
362 -- Return table listing all members of archive (sorted by name).
364 -- - member(string name)
365 -- Open substream for member name. The methods are the same as for io.opentextout. Note that
366 -- previous member must be closed before next can open.
367 -- - member_binary(string name)
368 -- Open binary (four to five) substream for member name. The methods are the same as
369 -- for io.openbinaryout. Note that previous substream must be closed before next can open.
371 -- Commit the file. No substream may be open. Closes the file.
373 -- Rollback the file. No substream may be open. Closes the file.
375 -- - io.open(string name, string mode) -> BinaryFile
376 -- Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
378 -- - io.open_read(string name) -> BinaryInput
379 -- Open file named @name as binary input stream.
380 -- - io.open_write(string name) -> BinaryOutput
381 -- Open file named @name as binary input stream.
382 -- - io.open_arch_read(string name) -> ArchiveIn
383 -- Open file named @name as input archive.
384 -- - io.open_arch_write(string name) -> ArchiveOut
385 -- Open file named @name as output archive.
386 -- - io.mkdir(string name)
387 -- Create directory name. Returns name created on success, nil on failure.
388 -- - io.unlink(string name)
389 -- Delete file/directory name. Returns name deleted on success, nil on failure.
390 -- - io.rename(string old, string new)
391 -- Rename file old -> new. Returns old, new on success, nil on failure.
392 -- - io.transform.text()
393 -- Returns function that calls text() method of its parameter.
394 -- - io.transform.four_to_five()
395 -- Returns function that calls four_to_five() method of its parameter.
396 -- - io.transform.deflate()
397 -- Returns function that calls deflate() method of its parameter.
398 -- - io.transform.inflate()
399 -- Returns function that calls inflate() method of its parameter.
400 -- - io.dotransform(object obj, function...)
401 -- Call specified functions on specified object. If any function fails (first argument nil
402 -- or false), call close method on preceeding object. Otherwise call specified functions
403 -- chained left to right and return the result.
404 -- - io.dotransform2(object obj, string err, function...)
405 -- Similar to dotransform except if obj is nil or false, returns obj, err.
408 local stopping = false;
409 local mesage_function = nil;
410 local lock_function = nil;
411 local uiaction_function = nil;
412 local stop_function = nil;
413 local attach_function = nil;
414 local _print_console_msg = print_console_msg;
416 local handle, err, chunk, indication, k, v;
418 local loadmod = loadmodule;
421 local export_module_in = function(tab, modname, prefix)
422 local fun = loadmod(modname);
424 _print_console_msg("Extension library " .. modname .. " not found");
427 for k, v in pairs(fun) do
428 tab[(prefix or "") .. k] = v;
436 jpcrr.memorysearch = {};
437 jpcrr.hostmemory = {};
442 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
443 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
444 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
445 export_module_in(jpcrr.events, "org.jpc.luaextensions.Events");
446 export_module_in(jpcrr.window, "org.jpc.luaextensions.Window");
447 export_module_in(bit, "org.jpc.luaextensions.Bitops");
448 export_module_in(jpcrr.memorysearch, "org.jpc.luaextensions.MemorySearch");
449 export_module_in(HUD, "org.jpc.luaextensions.HUD");
450 export_module_in(jpcrr.hostmemory, "org.jpc.luaextensions.HostMemory");
456 -- Few misc functions.
457 assert = function(val, err)
458 if (not val) and err then
464 modulus_split = function(number, ...)
465 local dividers = {...};
469 for k, v in ipairs(dividers) do
471 table.insert(results, (number - rem) / v);
475 table.insert(results, number);
476 return unpack(results);
479 jpcrr.register_redraw_function = function(f)
480 if f and type(f) ~= "function" then
481 error("Incorrect type of argument to register_redraw_function");
486 jpcrr.register_message_function = function(f)
487 if f and type(f) ~= "function" then
488 error("Incorrect type of argument to register_message_function");
490 message_function = f;
493 jpcrr.register_stop_function = function(f)
494 if f and type(f) ~= "function" then
495 error("Incorrect type of argument to register_stop_function");
500 jpcrr.register_attach_function = function(f)
501 if f and type(f) ~= "function" then
502 error("Incorrect type of argument to register_attach_function");
507 jpcrr.register_uiaction_function = function(f)
508 if f and type(f) ~= "function" then
509 error("Incorrect type of argument to register_uiaction_function");
511 uiaction_function = f;
516 local getmtable = getmetatable;
517 local toString = tostring;
518 local inject_binary_file;
519 local inject_binary_input;
520 local inject_binary_output;
521 local inject_text_input;
522 local inject_text_output;
523 local inject_archive_input;
524 local inject_archive_output;
526 -- Class member injectors.
527 inject_binary_file = function(obj, name)
529 getmtable(obj).name = function(obj)
532 getmtable(obj).__index = function(tab, name)
533 local x = getmtable(obj)[name];
537 error("Invalid method " .. name .. " for BinaryFile");
542 inject_binary_input = function(obj, underlying, name)
544 local old_four_to_five = getmtable(obj).four_to_five;
545 local old_inflate = getmtable(obj).inflate;
546 local old_text = getmtable(obj).text;
547 local old_read = getmtable(obj).read;
548 local old_close = getmtable(obj).close;
549 local underlying_object = underlying;
551 getmtable(obj).name = function(obj)
554 getmtable(obj).four_to_five = function(obj)
556 res, err = old_four_to_five(obj);
560 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
562 getmtable(obj).inflate = function(obj)
564 res, err = old_inflate(obj);
568 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
570 getmtable(obj).text = function(obj)
572 res, err = old_text(obj);
576 return inject_text_input(res, obj, "text<" .. _name .. ">");
578 getmtable(obj).read = function(obj, toread)
580 return old_read(obj, toread);
585 ret, err = old_read(obj, 16384);
596 getmtable(obj).close = function(obj)
597 local ret, err, ret2, err2;
598 ret, err = old_close(obj);
599 if underlying_object then ret2, err2 = underlying_object:close(); end
600 if ret and not ret2 then
606 getmtable(obj).__index = function(tab, name)
607 local x = getmtable(obj)[name];
611 error("Invalid method " .. name .. " for BinaryInput");
616 inject_binary_output = function(obj, underlying, name)
618 local old_four_to_five = getmtable(obj).four_to_five;
619 local old_deflate = getmtable(obj).deflate;
620 local old_text = getmtable(obj).text;
621 local old_close = getmtable(obj).close;
622 local underlying_object = underlying;
624 getmtable(obj).name = function(obj)
627 getmtable(obj).four_to_five = function(obj)
629 res, err = old_four_to_five(obj);
633 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
635 getmtable(obj).deflate = function(obj)
637 res, err = old_deflate(obj);
641 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
643 getmtable(obj).text = function(obj)
645 res, err = old_text(obj);
649 return inject_text_output(res, obj, "text<" .. _name .. ">");
651 getmtable(obj).close = function(obj)
652 local ret, err, ret2, err2;
653 ret, err = old_close(obj);
654 if underlying_object then ret2, err2 = underlying_object:close(); end
655 if ret and not ret2 then
661 getmtable(obj).__index = function(tab, name)
662 local x = getmtable(obj)[name];
666 error("Invalid method " .. name .. " for BinaryOutput");
671 inject_text_input = function(obj, underlying, name)
673 local old_close = getmtable(obj).close;
674 local underlying_object = underlying;
676 getmtable(obj).lines = function(obj)
677 return function(state, prevline)
681 getmtable(obj).name = function(obj)
684 getmtable(obj).close = function(obj)
685 local ret, err, ret2, err2;
686 ret, err = old_close(obj);
687 if underlying_object then ret2, err2 = underlying_object:close(); end
688 if ret and not ret2 then
694 getmtable(obj).__index = function(tab, name)
695 local x = getmtable(obj)[name];
699 error("Invalid method " .. name .. " for TextInput");
704 inject_text_output = function(obj, underlying, name)
706 local old_close = getmtable(obj).close;
707 local underlying_object = underlying;
709 getmtable(obj).name = function(obj)
712 getmtable(obj).close = function(obj)
713 local ret, err, ret2, err2;
714 ret, err = old_close(obj);
715 if underlying_object then ret2, err2 = underlying_object:close(); end
716 if ret and underlying_object then
722 getmtable(obj).__index = function(tab, name)
723 local x = getmtable(obj)[name];
727 error("Invalid method " .. name .. " for TextOutput");
732 inject_archive_input = function(obj, name)
734 local old_member = getmtable(obj).member;
735 local old_member_list = getmtable(obj).member_list;
736 getmtable(obj).member = function(obj, member)
738 res, err = old_member(obj, member);
742 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
744 getmtable(obj).name = function(obj)
747 getmtable(obj).member_list = function(obj)
748 local tab = old_member_list(obj);
749 if tab then table.sort(tab, jpcrr.stringlessthan); end
752 getmtable(obj).__index = function(tab, name)
753 local x = getmtable(obj)[name];
757 error("Invalid method " .. name .. " for ArchiveInput");
762 inject_archive_output = function(obj, name)
764 local old_member = getmtable(obj).member;
765 getmtable(obj).member = function(obj, member)
767 res, err = old_member(obj, member);
771 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
773 getmtable(obj).name = function(obj)
776 getmtable(obj).__index = function(tab, name)
777 local x = getmtable(obj)[name];
781 error("Invalid method " .. name .. " for ArchiveOutput");
787 -- Redefined routines.
789 local rprint = print_console_msg;
790 print_console_msg = nil;
791 print = function(...)
797 x = x .. "\t" .. toString(y[i]);
804 print_console_msg = nil;
810 local stringfind = string.find;
811 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
812 local selectname = loadmod("org.jpc.luaextensions.BaseFSOps").opensave_dialog;
813 local path = args["luapath"] or ".";
814 local toresourcename = function(resname, save, text)
816 return randname(path .. "/", "luatemp-");
819 if resname == "" and text then
821 a, b = selectname(save, text);
825 if stringfind(resname, "^/") then
827 error("Bad resource name (case 2): " .. resname);
830 a, b = selectname(save, string.sub(resname, 2));
834 if not stringfind(resname, "[%d%l%u_%-]") then
835 error("Bad resource name (case 1): " .. resname);
837 if stringfind(resname, "%.%.") then
838 error("Bad resource name (case 3): " .. resname);
840 if stringfind(resname, "\\") then
841 error("Bad resource name (case 4): " .. resname);
844 return resname, path .. "/" .. resname;
849 local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
850 local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
851 local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
852 local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
853 local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
855 local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
856 local mkdir = baseFS.mkdir;
857 local unlink = baseFS.unlink;
858 local rename = baseFS.rename;
860 local getmtable = getmetatable;
862 loadfile = function(_script)
863 local file, file2, err, content;
865 x, y = toresourcename(_script, false, "Select script to load");
866 if not x then return x, y; end
867 file, err = openbinin(y, "r");
869 return nil, "Can't open " .. _script .. ": " .. err;
871 file2, err = file:text();
873 return nil, "Can't transform " .. _script .. ": " .. err;
878 content = content .. line .. "\n";
883 return loadstring(content, _script);
886 io.open = function(name, mode)
891 _name, y = toresourcename(name, false, "Select file to read");
893 _name, y = toresourcename(name, true, "Select file to write");
895 if not _name then return _name, y; end
896 res, err = openbinary(y, mode);
900 return inject_binary_file(res, _name);
903 io.open_arch_read = function(name)
907 _name, y = toresourcename(name, false, "Select archive to read");
908 if not _name then return _name, y; end
909 res, err = openarchin(y);
913 return inject_archive_input(res, _name);
916 io.open_arch_write = function(name)
920 _name, y = toresourcename(name, true, "Select archive to write");
921 if not _name then return _name, y; end
922 res, err = openarchout(y);
926 return inject_archive_output(res, _name);
929 io.open_read = function(name)
933 _name, y = toresourcename(name, false, "Select file to read");
934 if not _name then return _name, y; end
935 res, err = openbinin(y);
939 return inject_binary_input(res, nil, _name);
942 io.open_write = function(name)
946 _name, y = toresourcename(name, true, "Select file to write");
947 if not _name then return _name, y; end
948 res, err = openbinout(y);
952 return inject_binary_output(res, nil, _name);
955 io.mkdir = function(name)
957 _name, y = toresourcename(name);
965 io.unlink = function(name)
967 _name, y = toresourcename(name);
975 io.rename = function(name1, name2)
978 _name, y = toresourcename(name1);
979 _name2, y2 = toresourcename(name2);
980 if rename(y, y2) then
981 return _name, _name2;
989 io.transform.text = function()
995 io.transform.four_to_five = function()
997 return obj:four_to_five();
1001 io.transform.inflate = function()
1002 return function(obj)
1003 return obj:inflate();
1007 io.transform.deflate = function()
1008 return function(obj)
1009 return obj:deflate();
1013 io.dotransform = function(obj, ...)
1017 for k, v in ipairs(todo) do
1028 io.dotransform2 = function(obj, err, ...)
1032 return io.dotransform(obj, err, ...);
1037 -- Various stuff built on top of ECI.
1038 local invoke = jpcrr.invoke;
1039 local invokecall = jpcrr.call;
1040 local invokesync = jpcrr.invoke_synchronous;
1042 jpcrr.sendevent = function(...)
1043 local arguments = {...};
1045 for k, v in ipairs(arguments) do
1046 arguments[k] = toString(v);
1048 invokesync("sendevent", arguments);
1051 jpcrr.sendevent_lowbound = function(...)
1052 local arguments = {...};
1054 for k, v in ipairs(arguments) do
1055 arguments[k] = toString(v);
1057 invokesync("sendevent-lowbound", arguments);
1060 jpcrr.save_state = function(name)
1061 local _name, _fname;
1062 _name, _fname = toresourcename(name, true, "File to savestate to");
1063 invokesync("state-save", {_fname});
1067 jpcrr.save_movie = function(name)
1068 local _name, _fname;
1069 _name, _fname = toresourcename(name, true, "File to save movie to");
1070 invokesync("movie-save", {_fname});
1074 jpcrr.load_state_normal = function(name)
1075 local _name, _fname;
1076 _name, _fname = toresourcename(name, false, "File to loadstate from");
1077 invokesync("state-load", {_fname});
1081 jpcrr.load_state_preserve_events = function(name)
1082 local _name, _fname;
1083 _name, _fname = toresourcename(name, false, "File to loadstate (preserve events) from");
1084 invokesync("state-load-noevents", {_fname});
1088 jpcrr.load_state_movie = function(name)
1089 local _name, _fname;
1090 _name, _fname = toresourcename(name, false, "File to load movie from");
1091 invokesync("movie-load", {_fname});
1095 jpcrr.assemble = function()
1096 invokesync("pc-assemble");
1099 jpcrr.change_authors = function()
1100 invokesync("change-authors");
1103 jpcrr.ram_dump = function(name, binary)
1104 local _name, _fname;
1105 _name, _fname = toresourcename(name, true, "Select file to ramdump to");
1107 invokesync("ram-dump-binary", {_fname});
1109 invokesync("ram-dump-text", {_fname});
1114 local poll_event = jpcrr.poll_event;
1115 local _print = print;
1116 local _unlock = jpcrr.release_vga;
1117 jpcrr.poll_event = function()
1119 local failed = false;
1121 a, b = poll_event();
1125 if a and a == "message" and message_function then
1126 a, b = pcall(message_function, b);
1128 _print("Error running message callback: " .. b);
1132 if a and a == "uiaction" and uiaction_function then
1133 a, b = pcall(uiaction_function, b);
1135 _print("Error running uiaction callback: " .. b);
1139 if a and a == "stop" and stop_function then
1140 a, b = pcall(stop_function);
1142 _print("Error running stop callback: " .. b);
1146 if a and a == "attach" and attach_function then
1147 a, b = pcall(attach_function);
1149 _print("Error running attach callback: " .. b);
1153 if a and a == "lock" and lock_function then
1154 a, b = pcall(lock_function);
1157 _print("Error running redraw callback: " .. b);
1164 if a and a == "lock" and stopping then
1173 local wait_event = jpcrr.wait_event;
1174 local _print = print;
1175 local _unlock = jpcrr.release_vga;
1176 jpcrr.wait_event = function()
1179 a, b = wait_event();
1180 if a and a == "message" and message_function then
1181 a, b = pcall(message_function, b);
1183 _print("Error running message callback: " .. b);
1187 if a and a == "uiaction" and uiaction_function then
1188 a, b = pcall(uiaction_function, b);
1190 _print("Error running uiaction callback: " .. b);
1194 if a and a == "stop" and stop_function then
1195 a, b = pcall(stop_function);
1197 _print("Error running stop callback: " .. b);
1201 if a and a == "attach" and attach_function then
1202 a, b = pcall(attach_function);
1204 _print("Error running attach callback: " .. b);
1208 if a and a == "lock" and lock_function then
1209 a, b = pcall(lock_function);
1212 _print("Error running redraw callback: " .. b);
1224 jpcrr.hud.left_gap = function(f, g)
1225 HUD("left_gap", f, g);
1228 jpcrr.hud.right_gap = function(f, g)
1229 HUD("right_gap", f, g);
1232 jpcrr.hud.top_gap = function(f, g)
1233 HUD("top_gap", f, g);
1236 jpcrr.hud.bottom_gap = function(f, g)
1237 HUD("bottom_gap", f, g);
1240 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
1241 HUD("hud_white_solid_box", f, x, y, w, h);
1244 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
1250 HUD("box", f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa);
1253 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1259 HUD("circle", f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1262 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1268 HUD("bitmap", f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1271 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1277 HUD("bitmap_binary", f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1280 jpcrr.hud.chargen = function(f, x, y, text, multiline, lr, lg, lb, la, fr, fg, fb, fa)
1286 HUD("vga_chargen", f, x, y, text, lr, lg, lb, la, fr, fg, fb, fa, multiline)
1289 jpcrr.shutdown_emulator = function()
1290 invokesync("shutdown-emulator", {});
1293 jpcrr.set_pccontrol_pos = function(x, y)
1294 invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
1297 jpcrr.set_luaplugin_pos = function(x, y)
1298 invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
1301 jpcrr.set_pcmonitor_pos = function(x, y)
1302 invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
1305 jpcrr.set_pcstartstoptest_pos = function(x, y)
1306 invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
1309 jpcrr.set_virtualkeyboard_pos = function(x, y)
1310 invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
1313 jpcrr.exit = function()
1314 invokesync("luaplugin-terminate");
1317 jpcrr.pc_start = function()
1321 jpcrr.pc_stop = function()
1322 invokesync("pc-stop");
1325 jpcrr.screenshot = function(include_hud)
1327 invoke("screenshot-renderbuffer");
1329 invoke("screenshot-vgabuffer");
1333 jpcrr.bios_kbd_trap = function(is_on)
1335 invokesync("trap-bios-kbd-on");
1337 invokesync("trap-bios-kbd-off");
1341 jpcrr.vretrace_start_trap = function(is_on)
1343 invokesync("trap-vretrace-start-on");
1345 invokesync("trap-vretrace-start-off");
1349 jpcrr.vretrace_end_trap = function(is_on)
1351 invokesync("trap-vretrace-end-on");
1353 invokesync("trap-vretrace-end-off");
1357 jpcrr.timed_trap = function(nsecs)
1359 invokesync("trap-timed", {toString(nsecs)});
1361 invokesync("trap-timed-disable");
1365 jpcrr.write_byte = function(addr, value)
1366 invokesync("memory-write", {toString(addr), toString(value), "1"});
1369 jpcrr.write_word = function(addr, value)
1370 invokesync("memory-write", {toString(addr), toString(value), "2"});
1373 jpcrr.write_dword = function(addr, value)
1374 invokesync("memory-write", {toString(addr), toString(value), "4"});
1377 jpcrr.read_byte = function(addr)
1378 local t = {toString(addr), "1"};
1379 t = invokecall("memory-read", t);
1380 return (t or {})[1];
1383 jpcrr.read_word = function(addr)
1384 local t = {toString(addr), "2"};
1385 t = invokecall("memory-read", t);
1386 return (t or {})[1];
1389 jpcrr.read_dword = function(addr)
1390 local t = {toString(addr), "4"};
1391 t = invokecall("memory-read", t);
1392 return (t or {})[1];
1395 jpcrr.read_byte_signed = function(addr)
1396 local t = {toString(addr), "1"};
1397 t = invokecall("memory-read", t);
1398 return bit.tosigned((t or {})[1], 7);
1401 jpcrr.read_word_signed = function(addr)
1402 local t = {toString(addr), "2"};
1403 t = invokecall("memory-read", t);
1404 return bit.tosigned((t or {})[1], 15);
1407 jpcrr.read_dword_signed = function(addr)
1408 local t = {toString(addr), "4"};
1409 t = invokecall("memory-read", t);
1410 return bit.tosigned((t or {})[1], 31);
1413 local e_wait_event = jpcrr.wait_event;
1414 local running = jpcrr.pc_running;
1415 local stop_and_execute_in_progress = false;
1416 jpcrr.stop_and_execute = function(f)
1419 if stop_and_execute_in_progress then
1422 if not running() then
1425 error("Error in after stop callback: " .. b);
1431 stop_and_execute_in_progress = true;
1432 a, b = e_wait_event();
1433 stop_and_execute_in_progress = false;
1434 if a and a == "lock" then
1439 elseif a and (a == "stop" or a == "attach") then
1446 error("Error in after stop callback: " .. b);
1453 jpcrr.invoke_synchronous = nil;
1457 dofile = function(_script)
1458 local chunk, err, indication
1459 chunk, err = loadfile(_script);
1461 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1469 for k, v in pairs(args2) do
1470 if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1471 args[string.sub(k, 3)] = v;
1478 loaded, err = pcall(function()
1479 chunk, err = loadfile(script);
1485 print("Kernel: Can't load script " .. script .. ": " .. err);
1486 invoke("luaplugin-terminate");
1491 indication, err = pcall(chunk);
1492 if not indication then
1493 print("Kernel: Unprotected error in script: " .. err);
1494 invoke("luaplugin-terminate");