JPC-RR r11.7
[jpcrr.git] / datafiles / luakernel
blob82da993b5132bfea2ed714ac02e20961281fc9c7
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_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
80 --              is no event).
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()
155 --              Exit the Lua VM.
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.
187 --      - jpcrr.pc_stop()
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
228 --              returns.
229 --      - jpcrr.hostmemory.read()
230 --              Returns contents of host memory.
231 --      - jpcrr.hostmemory.write(string contents)
232 --              Overwrites host memory with specified string.
233 --      - jpcrr.status()
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:
285 --              - name()
286 --                      Return name of file.
287 --              - length()
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.
295 --              - close()
296 --                      Close the file.
297 --      Class: BinaryInput:
298 --              Binary file for sequential input. Methods are as follows:
299 --              - name()
300 --                      Return name of file.
301 --              - four_to_five()
302 --                      Return BinaryInput that is four to five decoding of this stream.
303 --              - text()
304 --                      Return stream as TextInput.
305 --              - inflate()
306 --                      Return BinaryInput that is inflate of this stream.
307 --              - read(number bytes)
308 --                      Read up to bytes bytes from file.
309 --              - read()
310 --                      Read the entiere file at once.
311 --              - close()
312 --                      Close the file.
313 --              Character set for binary files is Latin-1.
315 --      Class: BinaryOutput:
316 --              Binary file for sequential output. Methods are as follows:
317 --              - name()
318 --                      Return name of file.
319 --              - four_to_five()
320 --                      Return BinaryOutput that writes four to five encoded output to this stream.
321 --              - text()
322 --                      Return stream as TextOutput.
323 --              - deflate()
324 --                      Return BinaryOutput that writes deflate output to this stream.
325 --              - write(string content)
326 --                      Write string to file.
327 --              - close()
328 --                      Close the file.
329 --              Character set for binary files is Latin-1.
331 --      Class: TextInput:
332 --              - name()
333 --                      Return name of file.
334 --              - read()
335 --                      Read line from file.
336 --              - read_component()
337 --                      Read next componented line into array.
338 --              - lines()
339 --                      Line iterator function.
340 --              - close()
341 --                      Close the file.
342 --      Character set for text files is UTF-8.
344 --      Class: TextOutput:
345 --              - name()
346 --                      Return name of file.
347 --              - write(string line)
348 --                      Write line line to file.
349 --              - write_component(table components)
350 --                      Write componented line.
351 --              - close()
352 --                      Close the file.
353 --              Character set for text files is UTF-8.
355 --      Class ArchiveIn:
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.
361 --              - close()
362 --                      Close the file. Any opened substreams are invalidated.
363 --              - member_list()
364 --                      Return table listing all members of archive (sorted by name).
365 --      Class ArchiveOut:
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.
372 --              - commit()
373 --                      Commit the file. No substream may be open. Closes the file.
374 --              - rollback()
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
379 --              write).
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;
435 loadmodule = nil;
437 local export_module_in = function(tab, modname, prefix)
438         local fun = loadmod(modname);
439         if not fun then
440                 _print_console_msg("Extension library " .. modname .. " not found");
441                 return nil;
442         end
443         for k, v in pairs(fun) do
444                 tab[(prefix or "") .. k] = v;
445         end
448 jpcrr = {};
449 jpcrr.hud = {};
450 jpcrr.events = {};
451 jpcrr.window = {};
452 jpcrr.memorysearch = {};
453 jpcrr.hostmemory = {};
454 jpcrr.random = {};
455 bit = {};
456 io = {};
457 local HUD = {};
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");
471 -- HUD bindings.
472 local HUD = HUD.HUD;
473 jpcrr.HUD = HUD;
475 -- Few misc functions.
476 assert = function(val, err)
477         if (not val) and err then
478                 error(err);
479         end
480         return val;
483 modulus_split = function(number, ...)
484         local dividers = {...};
485         local results = {};
486         local rem;
488         for k, v in ipairs(dividers) do
489                 rem = number % v;
490                 table.insert(results, (number - rem) / v);
491                 number = rem;
492         end
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");
501         end
502         lock_function = f;
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");
508         end
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");
515         end
516         stop_function = f;
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");
522         end
523         attach_function = f;
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");
529         end
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)
547         local _name = name;
548         getmtable(obj).name = function(obj)
549                 return _name;
550         end
551         getmtable(obj).__index = function(tab, name)
552                 local x = getmtable(obj)[name];
553                 if x then
554                         return x;
555                 end
556                 error("Invalid method " .. name .. " for BinaryFile");
557         end
558         return obj;
561 inject_binary_input = function(obj, underlying, name)
562         local _name = 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)
571                 return _name;
572         end
573         getmtable(obj).four_to_five = function(obj)
574                 local res, err;
575                 res, err = old_four_to_five(obj);
576                 if not res then
577                         return res, err;
578                 end
579                 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
580         end
581         getmtable(obj).inflate = function(obj)
582                 local res, err;
583                 res, err = old_inflate(obj);
584                 if not res then
585                         return res, err;
586                 end
587                 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
588         end
589         getmtable(obj).text = function(obj)
590                 local res, err;
591                 res, err = old_text(obj);
592                 if not res then
593                         return res, err;
594                 end
595                 return inject_text_input(res, obj, "text<" .. _name .. ">");
596         end
597         getmtable(obj).read = function(obj, toread)
598                 if toread then
599                         return old_read(obj, toread);
600                 else
601                         local res = "";
602                         local ret, err;
603                         while true do
604                                 ret, err = old_read(obj, 16384);
605                                 if not ret then
606                                         if not err then
607                                                 return res;
608                                         end
609                                         return nil, err;
610                                 end
611                                 res = res .. ret;
612                         end
613                 end
614         end
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
620                         err = err2;
621                         ret = ret2;
622                 end
623                 return ret, err;
624         end
625         getmtable(obj).__index = function(tab, name)
626                 local x = getmtable(obj)[name];
627                 if x then
628                         return x;
629                 end
630                 error("Invalid method " .. name .. " for BinaryInput");
631         end
632         return obj;
635 inject_binary_output = function(obj, underlying, name)
636         local _name = 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)
644                 return _name;
645         end
646         getmtable(obj).four_to_five = function(obj)
647                 local res, err;
648                 res, err = old_four_to_five(obj);
649                 if not res then
650                         return res, err;
651                 end
652                 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
653         end
654         getmtable(obj).deflate = function(obj)
655                 local res, err;
656                 res, err = old_deflate(obj);
657                 if not res then
658                         return res, err;
659                 end
660                 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
661         end
662         getmtable(obj).text = function(obj)
663                 local res, err;
664                 res, err = old_text(obj);
665                 if not res then
666                         return res, err;
667                 end
668                 return inject_text_output(res, obj, "text<" .. _name .. ">");
669         end
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
675                         err = err2;
676                         ret = ret2;
677                 end
678                 return ret, err;
679         end
680         getmtable(obj).__index = function(tab, name)
681                 local x = getmtable(obj)[name];
682                 if x then
683                         return x;
684                 end
685                 error("Invalid method " .. name .. " for BinaryOutput");
686         end
687         return obj;
690 inject_text_input = function(obj, underlying, name)
691         local _name = name;
692         local old_close = getmtable(obj).close;
693         local underlying_object = underlying;
695         getmtable(obj).lines = function(obj)
696                 return function(state, prevline)
697                         return state:read();
698                 end, obj, nil;
699         end
700         getmtable(obj).name = function(obj)
701                 return _name;
702         end
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
708                         err = err2;
709                         ret = ret2;
710                 end
711                 return ret, err;
712         end
713         getmtable(obj).__index = function(tab, name)
714                 local x = getmtable(obj)[name];
715                 if x then
716                         return x;
717                 end
718                 error("Invalid method " .. name .. " for TextInput");
719         end
720         return obj;
723 inject_text_output = function(obj, underlying, name)
724         local _name = name;
725         local old_close = getmtable(obj).close;
726         local underlying_object = underlying;
728         getmtable(obj).name = function(obj)
729                 return _name;
730         end
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
736                         err = err2;
737                         ret = ret2;
738                 end
739                 return ret, err;
740         end
741         getmtable(obj).__index = function(tab, name)
742                 local x = getmtable(obj)[name];
743                 if x then
744                         return x;
745                 end
746                 error("Invalid method " .. name .. " for TextOutput");
747         end
748         return obj;
751 inject_archive_input = function(obj, name)
752         local _name = name;
753         local old_member = getmtable(obj).member;
754         local old_member_list = getmtable(obj).member_list;
755         getmtable(obj).member = function(obj, member)
756                 local res, err;
757                 res, err = old_member(obj, member);
758                 if not res then
759                         return res, err;
760                 end
761                 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
762         end
763         getmtable(obj).name = function(obj)
764                 return _name;
765         end
766         getmtable(obj).member_list = function(obj)
767                 local tab = old_member_list(obj);
768                 if tab then table.sort(tab, jpcrr.stringlessthan); end
769                 return tab;
770         end
771         getmtable(obj).__index = function(tab, name)
772                 local x = getmtable(obj)[name];
773                 if x then
774                         return x;
775                 end
776                 error("Invalid method " .. name .. " for ArchiveInput");
777         end
778         return obj;
781 inject_archive_output = function(obj, name)
782         local _name = name;
783         local old_member = getmtable(obj).member;
784         getmtable(obj).member = function(obj, member)
785                 local res, err;
786                 res, err = old_member(obj, member);
787                 if not res then
788                         return res, err;
789                 end
790                 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
791         end
792         getmtable(obj).name = function(obj)
793                 return _name;
794         end
795         getmtable(obj).__index = function(tab, name)
796                 local x = getmtable(obj)[name];
797                 if x then
798                         return x;
799                 end
800                 error("Invalid method " .. name .. " for ArchiveOutput");
801         end
802         return obj;
806 -- Redefined routines.
808         local rprint = print_console_msg;
809         print_console_msg = nil;
810         print = function(...)
811                 local x = "";
812                 local y = {...};
813                 local i;
814                 for i = 1,#y do
815                         if i > 1 then
816                                 x = x .. "\t" .. toString(y[i]);
817                         else
818                                 x = toString(y[i]);
819                         end
820                 end
821                 rprint(x);
822         end
823         print_console_msg = nil;
828 -- I/O routines.
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)
834         if not resname then
835                 return randname(path .. "/", "luatemp-");
836         end
838         if resname == "" and text then
839                 local a, b;
840                 a, b = selectname(save, text);
841                 return a, (a or b);
842         end
844         if stringfind(resname, "^/") then
845                 if not text then
846                         error("Bad resource name (case 2): " .. resname);
847                 end
848                 local a, b;
849                 a, b = selectname(save, string.sub(resname, 2));
850                 return a, (a or b);
851         end
853         if not stringfind(resname, "[%d%l%u_%-]") then
854                 error("Bad resource name (case 1): " .. resname);
855         end
856         if stringfind(resname, "%.%.") then
857                 error("Bad resource name (case 3): " .. resname);
858         end
859         if stringfind(resname, "\\") then
860                 error("Bad resource name (case 4): " .. resname);
861         end
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;
883                 local x, y;
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");
887                 if not file then
888                         return nil, "Can't open " .. _script .. ": " .. err;
889                 end
890                 file2, err = file:text();
891                 if not file2 then
892                         return nil, "Can't transform " .. _script .. ": " .. err;
893                 end
894                 content = "";
895                 line = file2:read();
896                 while line do
897                         content = content .. line .. "\n";
898                         line = file2:read();
899                 end
900                 file2:close();
901                 file:close();
902                 return loadstring(content, _script);
903         end
905         io.open = function(name, mode)
906                 local _name;
907                 local res, err;
908                 local y;
909                 if mode == "r" then
910                         _name, y = toresourcename(name, false, "Select file to read");
911                 else
912                         _name, y = toresourcename(name, true, "Select file to write");
913                 end
914                 if not _name then return _name, y; end
915                 res, err = openbinary(y, mode);
916                 if not res then
917                         return res, err;
918                 end
919                 return inject_binary_file(res, _name);
920         end
922         io.open_arch_read = function(name)
923                 local _name = name;
924                 local res, err;
925                 local y;
926                 _name, y = toresourcename(name, false, "Select archive to read");
927                 if not _name then return _name, y; end
928                 res, err = openarchin(y);
929                 if not res then
930                         return res, err;
931                 end
932                 return inject_archive_input(res, _name);
933         end
935         io.open_arch_write = function(name)
936                 local _name = name;
937                 local res, err;
938                 local y;
939                 _name, y = toresourcename(name, true, "Select archive to write");
940                 if not _name then return _name, y; end
941                 res, err = openarchout(y);
942                 if not res then
943                         return res, err;
944                 end
945                 return inject_archive_output(res, _name);
946         end
948         io.open_read = function(name)
949                 local _name = name;
950                 local res, err;
951                 local y;
952                 _name, y = toresourcename(name, false, "Select file to read");
953                 if not _name then return _name, y; end
954                 res, err = openbinin(y);
955                 if not res then
956                         return res, err;
957                 end
958                 return inject_binary_input(res, nil, _name);
959         end
961         io.open_write = function(name)
962                 local _name = name;
963                 local res, err;
964                 local y;
965                 _name, y = toresourcename(name, true, "Select file to write");
966                 if not _name then return _name, y; end
967                 res, err = openbinout(y);
968                 if not res then
969                         return res, err;
970                 end
971                 return inject_binary_output(res, nil, _name);
972         end
974         io.mkdir = function(name)
975                 local _name, y;
976                 _name, y = toresourcename(name);
977                 if mkdir(y) then
978                         return _name;
979                 else
980                         return nil;
981                 end
982         end
984         io.unlink = function(name)
985                 local _name, y;
986                 _name, y = toresourcename(name);
987                 if unlink(y) then
988                         return _name;
989                 else
990                         return nil;
991                 end
992         end
994         io.rename = function(name1, name2)
995                 local _name, y;
996                 local _name2, y2;
997                 _name, y = toresourcename(name1);
998                 _name2, y2 = toresourcename(name2);
999                 if rename(y, y2) then
1000                         return _name, _name2;
1001                 else
1002                         return nil;
1003                 end
1004         end
1006         io.transform = {};
1008         io.transform.text = function()
1009                 return function(obj)
1010                         return obj:text();
1011                 end
1012         end
1014         io.transform.four_to_five = function()
1015                 return function(obj)
1016                         return obj:four_to_five();
1017                 end
1018         end
1020         io.transform.inflate = function()
1021                 return function(obj)
1022                         return obj:inflate();
1023                 end
1024         end
1026         io.transform.deflate = function()
1027                 return function(obj)
1028                         return obj:deflate();
1029                 end
1030         end
1032         io.dotransform = function(obj, ...)
1033                 local todo = {...};
1034                 local k, v;
1035                 local obj2, err;
1036                 for k, v in ipairs(todo) do
1037                         obj2, err = v(obj);
1038                         if not obj2 then
1039                                 obj:close();
1040                                 return nil, err;
1041                         end
1042                         obj = obj2;
1043                 end
1044                 return obj;
1045         end
1047         io.dotransform2 = function(obj, err, ...)
1048                 if not obj then
1049                         return obj, err;
1050                 end
1051                 return io.dotransform(obj, err, ...);
1052         end
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 = {...};
1063         local k, v;
1064         for k, v in ipairs(arguments) do
1065                 arguments[k] = toString(v);
1066         end
1067         invokesync("sendevent", arguments);
1070 jpcrr.sendevent_lowbound = function(...)
1071         local arguments = {...};
1072         local k, v;
1073         for k, v in ipairs(arguments) do
1074                 arguments[k] = toString(v);
1075         end
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});
1083         return _name;
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});
1090         return _name;
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});
1097         return _name;
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});
1104         return _name;
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});
1111         return _name;
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");
1125         if binary then
1126                 invokesync("ram-dump-binary", {_fname});
1127         else
1128                 invokesync("ram-dump-text", {_fname});
1129         end
1130         return _name;
1133 local poll_event = jpcrr.poll_event;
1134 local _print = print;
1135 local _unlock = jpcrr.release_vga;
1136 jpcrr.poll_event = function()
1137         local a, b;
1138         local failed = false;
1139         while not failed do
1140                 a, b = poll_event();
1141                 if not a then
1142                         failed = true;
1143                 end
1144                 if a and a == "message" and message_function then
1145                         a, b = pcall(message_function, b);
1146                         if not a then
1147                                 _print("Error running message callback: " .. b);
1148                         end
1149                         a = nil;
1150                 end
1151                 if a and a == "uiaction" and uiaction_function then
1152                         a, b = pcall(uiaction_function, b);
1153                         if not a then
1154                                 _print("Error running uiaction callback: " .. b);
1155                         end
1156                         a = nil;
1157                 end
1158                 if a and a == "stop" and stop_function then
1159                         a, b = pcall(stop_function);
1160                         if not a then
1161                                 _print("Error running stop callback: " .. b);
1162                         end
1163                         a = nil;
1164                 end
1165                 if a and a == "attach" and attach_function then
1166                         a, b = pcall(attach_function);
1167                         if not a then
1168                                 _print("Error running attach callback: " .. b);
1169                         end
1170                         a = nil;
1171                 end
1172                 if a and a == "lock" and lock_function then
1173                         a, b = pcall(lock_function);
1174                         _unlock();
1175                         if not a then
1176                                 _print("Error running redraw callback: " .. b);
1177                         end
1178                         if stoppping then
1179                                 return "lock";
1180                         end
1181                         a = nil;
1182                 end
1183                 if a and a == "lock" and stopping then
1184                         _unlock();
1185                         return "lock";
1186                 end
1187         end
1188         return a, b;
1192 local wait_event = jpcrr.wait_event;
1193 local _print = print;
1194 local _unlock = jpcrr.release_vga;
1195 jpcrr.wait_event = function()
1196         local a, b;
1197         while not a do
1198                 a, b = wait_event();
1199                 if a and a == "message" and message_function then
1200                         a, b = pcall(message_function, b);
1201                         if not a then
1202                                 _print("Error running message callback: " .. b);
1203                         end
1204                         a = nil;
1205                 end
1206                 if a and a == "uiaction" and uiaction_function then
1207                         a, b = pcall(uiaction_function, b);
1208                         if not a then
1209                                 _print("Error running uiaction callback: " .. b);
1210                         end
1211                         a = nil;
1212                 end
1213                 if a and a == "stop" and stop_function then
1214                         a, b = pcall(stop_function);
1215                         if not a then
1216                                 _print("Error running stop callback: " .. b);
1217                         end
1218                         a = nil;
1219                 end
1220                 if a and a == "attach" and attach_function then
1221                         a, b = pcall(attach_function);
1222                         if not a then
1223                                 _print("Error running attach callback: " .. b);
1224                         end
1225                         a = nil;
1226                 end
1227                 if a and a == "lock" and lock_function then
1228                         a, b = pcall(lock_function);
1229                         _unlock();
1230                         if not a then
1231                                 _print("Error running redraw callback: " .. b);
1232                         end
1233                         if stopping then
1234                                 return a, b;
1235                         end
1236                         a = nil;
1237                 end
1238         end
1239         return a, 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)
1264         la = la or 255;
1265         fr = fr or 0;
1266         fg = fg or 0;
1267         fb = fb or 0;
1268         fa = fa or 0;
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)
1273         la = la or 255;
1274         fr = fr or 0;
1275         fg = fg or 0;
1276         fb = fb or 0;
1277         fa = fa or 0;
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)
1282         la = la or 255;
1283         fr = fr or 0;
1284         fg = fg or 0;
1285         fb = fb or 0;
1286         fa = fa or 0;
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)
1291         la = la or 255;
1292         fr = fr or 0;
1293         fg = fg or 0;
1294         fb = fb or 0;
1295         fa = fa or 0;
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)
1300         la = la or 255;
1301         fr = fr or 0;
1302         fg = fg or 0;
1303         fb = fb or 0;
1304         fa = fa or 0;
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()
1337         invoke("pc-start");
1340 jpcrr.pc_stop = function()
1341         invokesync("pc-stop");
1344 jpcrr.screenshot = function(include_hud)
1345         if include_hud then
1346                 invoke("screenshot-renderbuffer");
1347         else
1348                 invoke("screenshot-vgabuffer");
1349         end
1352 jpcrr.bios_kbd_trap = function(is_on)
1353         if is_on then
1354                 invokesync("trap-bios-kbd-on");
1355         else
1356                 invokesync("trap-bios-kbd-off");
1357         end
1360 jpcrr.vretrace_start_trap = function(is_on)
1361         if is_on then
1362                 invokesync("trap-vretrace-start-on");
1363         else
1364                 invokesync("trap-vretrace-start-off");
1365         end
1368 jpcrr.vretrace_end_trap = function(is_on)
1369         if is_on then
1370                 invokesync("trap-vretrace-end-on");
1371         else
1372                 invokesync("trap-vretrace-end-off");
1373         end
1376 jpcrr.timed_trap = function(nsecs)
1377         if nsecs then
1378                 invokesync("trap-timed", {toString(nsecs)});
1379         else
1380                 invokesync("trap-timed-disable");
1381         end
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)
1436         local a, b;
1437         _unlock();
1438         if stop_and_execute_in_progress then
1439                 return false;
1440         end
1441         if not running() then
1442                 a, b = pcall(f);
1443                 if not a then
1444                         error("Error in after stop callback: " .. b);
1445                 end
1446                 return true;
1447         end
1448         jpcrr.pc_stop();
1449         while true do
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
1454                         _unlock();
1455                         if stopping then
1456                                 break;
1457                         end
1458                 elseif a and (a == "stop" or a == "attach") then
1459                         stopping = true;
1460                 end
1461         end
1462         stopping = false;
1463         a, b = pcall(f);
1464         if not a then
1465                 error("Error in after stop callback: " .. b);
1466         end
1467         return true;
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;
1476         end
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();
1488         if not status then
1489                 return nil;
1490         end
1491         return status.time;
1494 jpcrr.vga_edge_count = function()
1495         warn_legacy("jpcrr.vga_edge_count");
1496         local status = jpcrr.status();
1497         if not status then
1498                 return nil;
1499         end
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();
1512         if not status then
1513                 return nil;
1514         end
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();
1521         if not status then
1522                 return 0, 0;
1523         end
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();
1530         if not status then
1531                 return nil;
1532         end
1533         return status.irq0_dispatched, status.irq0_frequency;
1536 jpcrr.frame_number = function()
1537         warn_legacy("jpcrr.frame_number");
1538         local status = jpcrr.status();
1539         if not status then
1540                 return nil;
1541         end
1542         return status.frame;
1545 jpcrr.movie_rerecords = function()
1546         warn_legacy("jpcrr.movie_rerecords");
1547         local status = jpcrr.status();
1548         if not status then
1549                 return nil;
1550         end
1551         return status.movie_rerecords;
1554 jpcrr.movie_length = function()
1555         warn_legacy("jpcrr.movie_length");
1556         local status = jpcrr.status();
1557         if not status then
1558                 return nil;
1559         end
1560         return status.movie_length;
1563 jpcrr.movie_headers = function()
1564         warn_legacy("jpcrr.movie_headers");
1565         local status = jpcrr.status();
1566         if not status then
1567                 return nil;
1568         end
1569         return status.movie_headers;
1572 jpcrr.project_id = function()
1573         warn_legacy("jpcrr.project_id");
1574         local status = jpcrr.status();
1575         if not status then
1576                 return nil;
1577         end
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
1585                 return nil;
1586         end
1587         if not status.keyboard_leds_valid then
1588                 return false;
1589         end
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
1597                 return nil;
1598         end
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();
1606         if not status then
1607                 return nil;
1608         end
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;
1614 jpcrr.invoke = nil;
1615 jpcrr.invoke_synchronous = nil;
1616 jpcrr.call = null
1618 -- Dofile.
1619 dofile = function(_script)
1620         local chunk, err, indication
1621         chunk, err = loadfile(_script);
1622         if not chunk then
1623                 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1624         end
1625         return chunk();
1628 local args2 = args;
1629 args = null;
1630 args = {};
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;
1634         end
1636 jpcrr_raw = null;
1639         chunk = null;
1640         loaded, err = pcall(function()
1641                 chunk, err = loadfile(script);
1642                 if not chunk then
1643                         error(err);
1644                 end
1645         end);
1646         if not loaded then
1647                 print("Kernel: Can't load script " .. script .. ": " .. err);
1648                 invoke("luaplugin-terminate");
1649                 while true do end
1650         end
1652         script = null;
1653         indication, err = pcall(chunk);
1654         if not indication then
1655                 print("Kernel: Unprotected error in script: " .. err);
1656                 invoke("luaplugin-terminate");
1657                 while true do end
1658         end