Add call to shutdown PCRunner from Lua
[jpcrr.git] / datafiles / luakernel
blobc3fb03bc76c1afb45be624228dbf821a889dc1c9
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.tohex(number num)
51 --              Returns hexadecimal string representation of number.
52 --      - jpcrr.wait_message()
53 --              Waits for message (string) to come from message queue. Reutrns nil if interrupted.
54 --      - jpcrr.poll_message()
55 --              Checks if there is message from message queue. Reutrns message if there is one,
56 --              nil if none.
57 --      - jpcrr.wait_pc_stop()
58 --              Waits for PC execution to stop (but does not attempt to actually stop it).
59 --              If script is in frame hold, the frame hold is released.
60 --              Returns true if execution got stopped, false if interrupted.
61 --      - jpcrr.pc_running()
62 --              Returns true if PC is running.
63 --      - jpcrr.clock_time()
64 --              Returns current time or nil if no PC.
65 --      - jpcrr.pc_connected()
66 --              Returns true if PC is connected.
67 --      - jpcrr.wait_pc_attach()
68 --              Wait for PC to attach.
69 --      - jpcrr.next_frame()
70 --              Wait for next frame output hold.
71 --      - jpcrr.in_frame_hold()
72 --              Returns true if in frame hold, false otherwise.
73 --      - jpcrr.keypressed(number key)
74 --              Return true if key is pressed, else false.
75 --      - jpcrr.wait_vga()
76 --              Waits for VGA to enter frame hold mode. Frame hold happens once per frame.
77 --      - jpcrr.release_vga()
78 --              Allow VGA to exit frame hold mode. Wait for frame hold first.
79 --      - jpcrr.vga_resolution()
80 --              Return VGA x and y resolutions. -1x-1 or 0x0 is returned if no valid resolution.
81 --              Should only be called during frame hold.
82 --      - jpcrr.shutdown_emulator()
83 --              Shutdown the entiere emulator immediately (graceful shutdown, PCRunner only).
84 --      - jpcrr.hud.left_gap(number flags, number gap)
85 --              Set left gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
86 --              1 (2) is set, dump to video dump.
87 --      - jpcrr.hud.right_gap(number flags, number gap)
88 --              Set right gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
89 --              1 (2) is set, dump to video dump.
90 --      - jpcrr.hud.top_gap(number flags, number gap)
91 --              Set top gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
92 --              1 (2) is set, dump to video dump.
93 --      - jpcrr.hud.bottom_gap(number flags, number gap)
94 --              Set bottom gap for HUD. If flags has bit 0 (1) set, draw on screen, if bit
95 --              1 (2) is set, dump to video dump.
96 --      - jpcrr.hud.white_solid_box(number flags, number x, number y, number w, number h)
97 --              Draw with solid opaque box.
98 --      - jpcrr.hud.box(number flags, number x, number y, number w, number h, number linethick,
99 --                      number lineRed, number lineGreen, number lineBlue, number lineAlpha,
100 --                      number fillRed, number fillGreen, number fillBlue, number fillAlpha)
101 --              Draw box with specified size, border line thickness, line color and fill color.
102 --      - jpcrr.hud.circle(number flags, number x, number y, number r, number linethick,
103 --                      number lineRed, number lineGreen, number lineBlue, number lineAlpha,
104 --                      number fillRed, number fillGreen, number fillBlue, number fillAlpha)
105 --              Draw circle with specified size, border line thickness, line color and fill color.
106 --      - jpcrr.hud.bitmap(number flags, number x, number y, string bmap,
107 --                      number fgRed, number fgGreen, number fgBlue, number fgAlpha,
108 --                      number bgRed, number bgGreen, number bgBlue, number bgAlpha)
109 --              Draw bitmap with specified foreground color and background color.
110 --      - jpcrr.hud.bitmap_binary(number flags, number x, number y, string bmap,
111 --                      number fgRed, number fgGreen, number fgBlue, number fgAlpha,
112 --                      number bgRed, number bgGreen, number bgBlue, number bgAlpha)
113 --              Draw binary bitmap with specified foreground color and background color.
114 --      - jpcrr.joystick_state()
115 --              Returns nil if no joystick. Otherwise returns hold times for all four axis (numeric)
116 --              followed by button states (boolean).
117 --      - jpcrr.keyboard_leds()
118 --              Returns nil if no keyboard, false if LED status is unknown. Otherwise returns three
119 --              booleans, first being state of num lock, second being state of caps lock and third
120 --              being state of scroll lock.
121 --      - jpcrr.mouse_state()
122 --              Returns nil if no mouse. Otherwise returns X, Y and Z axis pending motions (numeric)
123 --              followed by button states (5 booleans).
124 --      - jpcrr.component_encode(table components)
125 --              Return component encoding for specified components.
126 --      - jpcrr.component_decode(string line)
127 --              Return component decoding for specified line, nil/nil if it doesn't encode
128 --              anything, nil/string if parse error occurs (the error is the second return).
129 --      - jpcrr.save_state(string name)
130 --              Savestate into specified file. Returns name used.
131 --      - jpcrr.save_movie(string name)
132 --              Save movie into specified file. Returns name used.
133 --      - jpcrr.load_state_normal(string name)
134 --              Load specified savestate. Returns name used.
135 --      - jpcrr.load_state_preserve_events(string name)
136 --              Load specified savestate, preserving events. Returns name used.
137 --      - jpcrr.load_state_movie(string name)
138 --              Load specified savestate as movie. Returns name used.
139 --      - jpcrr.assemble()
140 --              Open system settings dialog.
141 --      - jpcrr.change_authors()
142 --              Open change authors dialog.
143 --      - jpcrr.exit = function()
144 --              Exit the Lua VM.
145 --      - jpcrr.ram_dump(string name, boolean binary)
146 --              Dump PC memory to specified file. If binary is true, dump is binary, otherwise
147 --              textual hexadecimal dump.
148 --      - jpcrr.write_byte(number addr, number value)
149 --              Write byte to specified physical address.
150 --      - jpcrr.write_word(number addr, number value)
151 --              Write word to specified physical address (little endian).
152 --      - jpcrr.write_dword(number addr, number value)
153 --              Write dword to specified physical address (little endian).
154 --      - jpcrr.read_byte(number addr)
155 --              Return byte from specified physical address.
156 --      - jpcrr.read_word(number addr)
157 --              Return word from specified physical address (little endian).
158 --      - jpcrr.read_dword(number addr)
159 --              Return dword from specified physical address (little endian).
160 --      - jpcrr.timed_trap(number nsecs)
161 --              Set trap after specified number of nanoseconds. Use nil as nsecs to disable.
162 --      - jpcrr.vretrace_start_trap(boolean is_on)
163 --              Set trap on vretrace start on/off.
164 --      - jpcrr.vretrace_end_trap(boolean is_on)
165 --              Set trap on vretrace end on/off.
166 --      - jpcrr.pc_start()
167 --              Start PC execution.
168 --      - jpcrr.pc_stop()
169 --              Stop PC execution.
170 --      - jpcrr.set_pccontrol_pos(number x, number y)
171 --              Set position of PCControl window.
172 --      - jpcrr.set_luaplugin_pos(number x, number y)
173 --              Set position of LuaPlugin window.
174 --      - jpcrr.set_pcmonitor_pos(number x, number y)
175 --              Set position of PCMonitor window.
176 --      - jpcrr.set_pcstartstoptest_pos(number x, number y)
177 --              Set position of PCStartStopTest window.
178 --      - jpcrr.set_virtualkeyboard_pos(number x, number y)
179 --              Set position of VirtualKeyboard window.
180 --      - jpcrr.stringlessthan(String x, String y)
181 --              Return true if x is before y in codepoint lexical order, otherwise false.
182 --      - jpcrr.screenshot(boolean include_hud)
183 --              Take screen shot (Requires monitor). If include_hud is true, include HUD
184 --              (as shown on screen). Note that this should only be called during frame
185 --              hold or results are pretty much undefined.
186 --      - jpcrr.sendevent(string/number...)
187 --              Sends specified event.
188 --      - jpcrr.movie_rerecords()
189 --              Return number of rerecords (nil if no movie loaded).
190 --      - jpcrr.movie_length()
191 --              Return length of movie in ns (nil if no movie loaded).
192 --      - jpcrr.movie_headers()
193 --              Return headers of movie as array of arrays (nil if no movie loaded).
195 --      I/O functions have the following conventions. If function returns any real data, the first
196 --      return value returns this data or is nil. Otherwise first return value is true or false.
197 --      If first return value is nil or false, then the second return value gives textual error
198 --      message for failed operation, or is nil if EOF occured before anything was read.
200 --      Unlink, rename and mkdir don't follow this pattern. They just return true/false to signal
201 --      success or failure.
203 --      Specifying nil as name of file results random filename being used (it even works with unlink,
204 --      mkdir, rename and read-only access, but doesn't make any sense there).
206 --      Specifying empty filename prompts for file (doesn't work with mkdir, rename nor unlink). Use
207 --      '/<title>' to specify title for prompt dialog.
209 --      Class: BinaryFile:
210 --              Binary file for RO or RW access. Methods are as follows:
211 --              - name()
212 --                      Return name of file.
213 --              - length()
214 --                      Return length of file.
215 --              - set_length(number length)
216 --                      Truncate file to specified length
217 --              - read(number offset, number length)
218 --                      Read up to length bytes from offset.
219 --              - write(number offset, string content)
220 --                      Write content to specified offset.
221 --              - close()
222 --                      Close the file.
223 --      Class: BinaryInput:
224 --              Binary file for sequential input. Methods are as follows:
225 --              - name()
226 --                      Return name of file.
227 --              - four_to_five()
228 --                      Return BinaryInput that is four to five decoding of this stream.
229 --              - text()
230 --                      Return stream as TextInput.
231 --              - inflate()
232 --                      Return BinaryInput that is inflate of this stream.
233 --              - read(number bytes)
234 --                      Read up to bytes bytes from file.
235 --              - read()
236 --                      Read the entiere file at once.
237 --              - close()
238 --                      Close the file.
239 --              Character set for binary files is Latin-1.
241 --      Class: BinaryOutput:
242 --              Binary file for sequential output. Methods are as follows:
243 --              - name()
244 --                      Return name of file.
245 --              - four_to_five()
246 --                      Return BinaryOutput that writes four to five encoded output to this stream.
247 --              - text()
248 --                      Return stream as TextOutput.
249 --              - deflate()
250 --                      Return BinaryOutput that writes deflate output to this stream.
251 --              - write(string content)
252 --                      Write string to file.
253 --              - close()
254 --                      Close the file.
255 --              Character set for binary files is Latin-1.
257 --      Class: TextInput:
258 --              - name()
259 --                      Return name of file.
260 --              - read()
261 --                      Read line from file.
262 --              - read_component()
263 --                      Read next componented line into array.
264 --              - lines()
265 --                      Line iterator function.
266 --              - close()
267 --                      Close the file.
268 --      Character set for text files is UTF-8.
270 --      Class: TextOutput:
271 --              - name()
272 --                      Return name of file.
273 --              - write(string line)
274 --                      Write line line to file.
275 --              - write_component(table components)
276 --                      Write componented line.
277 --              - close()
278 --                      Close the file.
279 --              Character set for text files is UTF-8.
281 --      Class ArchiveIn:
282 --              - member(string name)
283 --                      Open substream for member name. The methods are the same as for io.opentextin.
284 --              - member_binary(string name)
285 --                      Open binary (four to five) substream for member name. The methods are the same as
286 --                      for io.openbinaryin.
287 --              - close()
288 --                      Close the file. Any opened substreams are invalidated.
289 --              - member_list()
290 --                      Return table listing all members of archive (sorted by name).
291 --      Class ArchiveOut:
292 --              - member(string name)
293 --                      Open substream for member name. The methods are the same as for io.opentextout. Note that
294 --                      previous member must be closed before next can open.
295 --              - member_binary(string name)
296 --                      Open binary (four to five) substream for member name. The methods are the same as
297 --                      for io.openbinaryout. Note that previous substream must be closed before next can open.
298 --              - commit()
299 --                      Commit the file. No substream may be open. Closes the file.
300 --              - rollback()
301 --                      Rollback the file. No substream may be open. Closes the file.
303 --      - io.open(string name, string mode) -> BinaryFile
304 --              Open file named @name in specified mode. The mode can be 'r' (read only) or 'rw' (read and
305 --              write).
306 --      - io.open_read(string name) -> BinaryInput
307 --              Open file named @name as binary input stream.
308 --      - io.open_write(string name) -> BinaryOutput
309 --              Open file named @name as binary input stream.
310 --      - io.open_arch_read(string name) -> ArchiveIn
311 --              Open file named @name as input archive.
312 --      - io.open_arch_write(string name) -> ArchiveOut
313 --              Open file named @name as output archive.
314 --      - io.mkdir(string name)
315 --              Create directory name. Returns name created on success, nil on failure.
316 --      - io.unlink(string name)
317 --              Delete file/directory name. Returns name deleted on success, nil on failure.
318 --      - io.rename(string old, string new)
319 --              Rename file old -> new. Returns old, new on success, nil on failure.
320 --      - io.transform.text()
321 --              Returns function that calls text() method of its parameter.
322 --      - io.transform.four_to_five()
323 --              Returns function that calls four_to_five() method of its parameter.
324 --      - io.transform.deflate()
325 --              Returns function that calls deflate() method of its parameter.
326 --      - io.transform.inflate()
327 --              Returns function that calls inflate() method of its parameter.
328 --      - io.dotransform(object obj, function...)
329 --              Call specified functions on specified object. If any function fails (first argument nil
330 --              or false), call close method on preceeding object. Otherwise call specified functions
331 --              chained left to right and return the result.
332 --      - io.dotransform2(object obj, string err, function...)
333 --              Similar to dotransform except if obj is nil or false, returns obj, err.
339 local handle, err, chunk, indication, k, v;
341 local loadmod = loadmodule;
342 loadmodule = nil;
344 local export_module_in = function(tab, modname, prefix)
345         local fun = loadmod(modname);
346         for k, v in pairs(fun) do
347                 tab[(prefix or "") .. k] = v;
348         end
351 jpcrr = {};
352 jpcrr.hud = {};
353 bit = {};
354 io = {};
356 export_module_in(jpcrr, "org.jpc.luaextensions.Base");
357 export_module_in(jpcrr, "org.jpc.luaextensions.InputDevices");
358 export_module_in(jpcrr, "org.jpc.luaextensions.ComponentCoding", "component_");
359 export_module_in(bit, "org.jpc.luaextensions.Bitops");
361 -- Few misc functions.
362 assert = function(val, err)
363         if (not val) and err then
364                 error(err);
365         end
366         return val;
369 modulus_split = function(number, ...)
370         local dividers = {...};
371         local results = {};
372         local rem;
374         for k, v in ipairs(dividers) do
375                 rem = number % v;
376                 table.insert(results, (number - rem) / v);
377                 number = rem;
378         end
380         table.insert(results, number);
381         return unpack(results);
384 local getmtable = getmetatable;
385 local toString = tostring;
386 local inject_binary_file;
387 local inject_binary_input;
388 local inject_binary_output;
389 local inject_text_input;
390 local inject_text_output;
391 local inject_archive_input;
392 local inject_archive_output;
394 -- Class member injectors.
395 inject_binary_file = function(obj, name)
396         local _name = name;
397         getmtable(obj).name = function(obj)
398                 return _name;
399         end
400         getmtable(obj).__index = function(tab, name)
401                 local x = getmtable(obj)[name];
402                 if x then
403                         return x;
404                 end
405                 error("Invalid method " .. name .. " for BinaryFile");
406         end
407         return obj;
410 inject_binary_input = function(obj, underlying, name)
411         local _name = name;
412         local old_four_to_five = getmtable(obj).four_to_five;
413         local old_inflate = getmtable(obj).inflate;
414         local old_text = getmtable(obj).text;
415         local old_read = getmtable(obj).read;
416         local old_close = getmtable(obj).close;
417         local underlying_object = underlying;
419         getmtable(obj).name = function(obj)
420                 return _name;
421         end
422         getmtable(obj).four_to_five = function(obj)
423                 local res, err;
424                 res, err = old_four_to_five(obj);
425                 if not res then
426                         return res, err;
427                 end
428                 return inject_binary_input(res, obj, "four-to-five<" .. _name .. ">");
429         end
430         getmtable(obj).inflate = function(obj)
431                 local res, err;
432                 res, err = old_inflate(obj);
433                 if not res then
434                         return res, err;
435                 end
436                 return inject_binary_input(res, obj, "inflate<" .. _name .. ">");
437         end
438         getmtable(obj).text = function(obj)
439                 local res, err;
440                 res, err = old_text(obj);
441                 if not res then
442                         return res, err;
443                 end
444                 return inject_text_input(res, obj, "text<" .. _name .. ">");
445         end
446         getmtable(obj).read = function(obj, toread)
447                 if toread then
448                         return old_read(obj, toread);
449                 else
450                         local res = "";
451                         local ret, err;
452                         while true do
453                                 ret, err = old_read(obj, 16384);
454                                 if not ret then
455                                         if not err then
456                                                 return res;
457                                         end
458                                         return nil, err;
459                                 end
460                                 res = res .. ret;
461                         end
462                 end
463         end
464         getmtable(obj).close = function(obj)
465                 local ret, err, ret2, err2;
466                 ret, err = old_close(obj);
467                 if underlying_object then ret2, err2 = underlying_object:close(); end
468                 if ret and not ret2 then
469                         err = err2;
470                         ret = ret2;
471                 end
472                 return ret, err;
473         end
474         getmtable(obj).__index = function(tab, name)
475                 local x = getmtable(obj)[name];
476                 if x then
477                         return x;
478                 end
479                 error("Invalid method " .. name .. " for BinaryInput");
480         end
481         return obj;
484 inject_binary_output = function(obj, underlying, name)
485         local _name = name;
486         local old_four_to_five = getmtable(obj).four_to_five;
487         local old_deflate = getmtable(obj).deflate;
488         local old_text = getmtable(obj).text;
489         local old_close = getmtable(obj).close;
490         local underlying_object = underlying;
492         getmtable(obj).name = function(obj)
493                 return _name;
494         end
495         getmtable(obj).four_to_five = function(obj)
496                 local res, err;
497                 res, err = old_four_to_five(obj);
498                 if not res then
499                         return res, err;
500                 end
501                 return inject_binary_output(res, obj, "four-to-five<" .. _name .. ">");
502         end
503         getmtable(obj).deflate = function(obj)
504                 local res, err;
505                 res, err = old_deflate(obj);
506                 if not res then
507                         return res, err;
508                 end
509                 return inject_binary_output(res, obj, "deflate<" .. _name .. ">");
510         end
511         getmtable(obj).text = function(obj)
512                 local res, err;
513                 res, err = old_text(obj);
514                 if not res then
515                         return res, err;
516                 end
517                 return inject_text_output(res, obj, "text<" .. _name .. ">");
518         end
519         getmtable(obj).close = function(obj)
520                 local ret, err, ret2, err2;
521                 ret, err = old_close(obj);
522                 if underlying_object then ret2, err2 = underlying_object:close(); end
523                 if ret and not ret2 then
524                         err = err2;
525                         ret = ret2;
526                 end
527                 return ret, err;
528         end
529         getmtable(obj).__index = function(tab, name)
530                 local x = getmtable(obj)[name];
531                 if x then
532                         return x;
533                 end
534                 error("Invalid method " .. name .. " for BinaryOutput");
535         end
536         return obj;
539 inject_text_input = function(obj, underlying, name)
540         local _name = name;
541         local old_close = getmtable(obj).close;
542         local underlying_object = underlying;
544         getmtable(obj).lines = function(obj)
545                 return function(state, prevline)
546                         return state:read();
547                 end, obj, nil;
548         end
549         getmtable(obj).name = function(obj)
550                 return _name;
551         end
552         getmtable(obj).close = function(obj)
553                 local ret, err, ret2, err2;
554                 ret, err = old_close(obj);
555                 if underlying_object then ret2, err2 = underlying_object:close(); end
556                 if ret and not ret2 then
557                         err = err2;
558                         ret = ret2;
559                 end
560                 return ret, err;
561         end
562         getmtable(obj).__index = function(tab, name)
563                 local x = getmtable(obj)[name];
564                 if x then
565                         return x;
566                 end
567                 error("Invalid method " .. name .. " for TextInput");
568         end
569         return obj;
572 inject_text_output = function(obj, underlying, name)
573         local _name = name;
574         local old_close = getmtable(obj).close;
575         local underlying_object = underlying;
577         getmtable(obj).name = function(obj)
578                 return _name;
579         end
580         getmtable(obj).close = function(obj)
581                 local ret, err, ret2, err2;
582                 ret, err = old_close(obj);
583                 if underlying_object then ret2, err2 = underlying_object:close(); end
584                 if ret and underlying_object then
585                         err = err2;
586                         ret = ret2;
587                 end
588                 return ret, err;
589         end
590         getmtable(obj).__index = function(tab, name)
591                 local x = getmtable(obj)[name];
592                 if x then
593                         return x;
594                 end
595                 error("Invalid method " .. name .. " for TextOutput");
596         end
597         return obj;
600 inject_archive_input = function(obj, name)
601         local _name = name;
602         local old_member = getmtable(obj).member;
603         local old_member_list = getmtable(obj).member_list;
604         getmtable(obj).member = function(obj, member)
605                 local res, err;
606                 res, err = old_member(obj, member);
607                 if not res then
608                         return res, err;
609                 end
610                 return inject_binary_input(res, nil, _name .. "[" .. member .. "]");
611         end
612         getmtable(obj).name = function(obj)
613                 return _name;
614         end
615         getmtable(obj).member_list = function(obj)
616                 local tab = old_member_list(obj);
617                 if tab then table.sort(tab, jpcrr.stringlessthan); end
618                 return tab;
619         end
620         getmtable(obj).__index = function(tab, name)
621                 local x = getmtable(obj)[name];
622                 if x then
623                         return x;
624                 end
625                 error("Invalid method " .. name .. " for ArchiveInput");
626         end
627         return obj;
630 inject_archive_output = function(obj, name)
631         local _name = name;
632         local old_member = getmtable(obj).member;
633         getmtable(obj).member = function(obj, member)
634                 local res, err;
635                 res, err = old_member(obj, member);
636                 if not res then
637                         return res, err;
638                 end
639                 return inject_binary_output(res, nil, _name .. "[" .. member .. "]");
640         end
641         getmtable(obj).name = function(obj)
642                 return _name;
643         end
644         getmtable(obj).__index = function(tab, name)
645                 local x = getmtable(obj)[name];
646                 if x then
647                         return x;
648                 end
649                 error("Invalid method " .. name .. " for ArchiveOutput");
650         end
651         return obj;
655 -- Redefined print.
657         local rprint = print_console_msg;
658         print_console_msg = nil;
659         print = function(...)
660                 local x = "";
661                 local y = {...};
662                 local i;
663                 for i = 1,#y do
664                         if i > 1 then
665                                 x = x .. "\t" .. toString(y[i]);
666                         else
667                                 x = toString(y[i]);
668                         end
669                 end
670                 rprint(x);
671         end
672         print_console_msg = nil;
675 -- I/O routines.
676 local stringfind = string.find;
677 local randname = loadmod("org.jpc.luaextensions.DelayedDelete").random_temp_name;
678 local selectname = loadmod("org.jpc.luaextensions.BaseFSOps").opensave_dialog;
679 local path = args["luapath"] or ".";
680 local toresourcename = function(resname, save, text)
681         if not resname then
682                 return randname(path .. "/", "luatemp-");
683         end
685         if resname == "" and text then
686                 local a, b;
687                 a, b = selectname(save, text);
688                 return a, (a or b);
689         end
691         if stringfind(resname, "^/") then
692                 if not text then
693                         error("Bad resource name (case 2): " .. resname);
694                 end
695                 local a, b;
696                 a, b = selectname(save, string.sub(resname, 2));
697                 return a, (a or b);
698         end
700         if not stringfind(resname, "[%d%l%u_%-]") then
701                 error("Bad resource name (case 1): " .. resname);
702         end
703         if stringfind(resname, "%.%.") then
704                 error("Bad resource name (case 3): " .. resname);
705         end
706         if stringfind(resname, "\\") then
707                 error("Bad resource name (case 4): " .. resname);
708         end
710         return resname, path .. "/" .. resname;
715         local openbinin = loadmod("org.jpc.luaextensions.BinaryInFile").open;
716         local openbinout = loadmod("org.jpc.luaextensions.BinaryOutFile").open;
717         local openarchin = loadmod("org.jpc.luaextensions.ArchiveIn").open;
718         local openarchout = loadmod("org.jpc.luaextensions.ArchiveOut").open;
719         local openbinary = loadmod("org.jpc.luaextensions.BinaryFile").open;
721         local baseFS = loadmod("org.jpc.luaextensions.BaseFSOps");
722         local mkdir = baseFS.mkdir;
723         local unlink = baseFS.unlink;
724         local rename = baseFS.rename;
726         local getmtable = getmetatable;
728         loadfile = function(_script)
729                 local file, file2, err, content;
730                 local x, y;
731                 x, y = toresourcename(_script, false, "Select script to load");
732                 if not x then return x, y; end
733                 file, err = openbinin(y, "r");
734                 if not file then
735                         return nil, "Can't open " .. _script .. ": " .. err;
736                 end
737                 file2, err = file:text();
738                 if not file2 then
739                         return nil, "Can't transform " .. _script .. ": " .. err;
740                 end
741                 content = "";
742                 line = file2:read();
743                 while line do
744                         content = content .. line .. "\n";
745                         line = file2:read();
746                 end
747                 file2:close();
748                 file:close();
749                 return loadstring(content, _script);
750         end
752         io.open = function(name, mode)
753                 local _name;
754                 local res, err;
755                 local y;
756                 if mode == "r" then
757                         _name, y = toresourcename(name, false, "Select file to read");
758                 else
759                         _name, y = toresourcename(name, true, "Select file to write");
760                 end
761                 if not _name then return _name, y; end
762                 res, err = openbinary(y, mode);
763                 if not res then
764                         return res, err;
765                 end
766                 return inject_binary_file(res, _name);
767         end
769         io.open_arch_read = function(name)
770                 local _name = name;
771                 local res, err;
772                 local y;
773                 _name, y = toresourcename(name, false, "Select archive to read");
774                 if not _name then return _name, y; end
775                 res, err = openarchin(y);
776                 if not res then
777                         return res, err;
778                 end
779                 return inject_archive_input(res, _name);
780         end
782         io.open_arch_write = function(name)
783                 local _name = name;
784                 local res, err;
785                 local y;
786                 _name, y = toresourcename(name, true, "Select archive to write");
787                 if not _name then return _name, y; end
788                 res, err = openarchout(y);
789                 if not res then
790                         return res, err;
791                 end
792                 return inject_archive_output(res, _name);
793         end
795         io.open_read = function(name)
796                 local _name = name;
797                 local res, err;
798                 local y;
799                 _name, y = toresourcename(name, false, "Select file to read");
800                 if not _name then return _name, y; end
801                 res, err = openbinin(y);
802                 if not res then
803                         return res, err;
804                 end
805                 return inject_binary_input(res, nil, _name);
806         end
808         io.open_write = function(name)
809                 local _name = name;
810                 local res, err;
811                 local y;
812                 _name, y = toresourcename(name, true, "Select file to write");
813                 if not _name then return _name, y; end
814                 res, err = openbinout(y);
815                 if not res then
816                         return res, err;
817                 end
818                 return inject_binary_output(res, nil, _name);
819         end
821         io.mkdir = function(name)
822                 local _name, y;
823                 _name, y = toresourcename(name);
824                 if mkdir(y) then
825                         return _name;
826                 else
827                         return nil;
828                 end
829         end
831         io.unlink = function(name)
832                 local _name, y;
833                 _name, y = toresourcename(name);
834                 if unlink(y) then
835                         return _name;
836                 else
837                         return nil;
838                 end
839         end
841         io.rename = function(name1, name2)
842                 local _name, y;
843                 local _name2, y2;
844                 _name, y = toresourcename(name1);
845                 _name2, y2 = toresourcename(name2);
846                 if rename(y, y2) then
847                         return _name, _name2;
848                 else
849                         return nil;
850                 end
851         end
853         io.transform = {};
855         io.transform.text = function()
856                 return function(obj)
857                         return obj:text();
858                 end
859         end
861         io.transform.four_to_five = function()
862                 return function(obj)
863                         return obj:four_to_five();
864                 end
865         end
867         io.transform.inflate = function()
868                 return function(obj)
869                         return obj:inflate();
870                 end
871         end
873         io.transform.deflate = function()
874                 return function(obj)
875                         return obj:deflate();
876                 end
877         end
879         io.dotransform = function(obj, ...)
880                 local todo = {...};
881                 local k, v;
882                 local obj2, err;
883                 for k, v in ipairs(todo) do
884                         obj2, err = v(obj);
885                         if not obj2 then
886                                 obj:close();
887                                 return nil, err;
888                         end
889                         obj = obj2;
890                 end
891                 return obj;
892         end
894         io.dotransform2 = function(obj, err, ...)
895                 if not obj then
896                         return obj, err;
897                 end
898                 return io.dotransform(obj, err, ...);
899         end
903 jpcrr.next_frame = function(name)
904         while true do
905                 if not jpcrr.pc_connected() then
906                         jpcrr.wait_pc_attach();
907                 end
908                 if jpcrr.in_frame_hold() then
909                         jpcrr.release_vga();
910                 end
911                 if jpcrr.wait_vga() then
912                         return;
913                 end
914         end
918 -- Various stuff built on top of ECI.
919 local invoke = jpcrr.invoke;
920 local invokecall = jpcrr.call;
921 local invokesync = jpcrr.invoke_synchronous;
923 jpcrr.sendevent = function(...)
924         local arguments = {...};
925         local k, v;
926         for k, v in ipairs(arguments) do
927                 arguments[k] = toString(v);
928         end
929         invokesync("sendevent", arguments);
932 jpcrr.save_state = function(name)
933         local _name, _fname;
934         _name, _fname = toresourcename(name);
935         invokesync("state-save", {_fname});
936         return _name;
939 jpcrr.save_movie = function(name)
940         local _name, _fname;
941         _name, _fname = toresourcename(name);
942         invokesync("movie-save", {_name});
943         return _name;
946 jpcrr.load_state_normal = function(name)
947         local _name, _fname;
948         _name, _fname = toresourcename(name);
949         invokesync("state-load", {_name});
950         return _name;
953 jpcrr.load_state_preserve_events = function(name)
954         local _name, _fname;
955         _name, _fname = toresourcename(name);
956         invokesync("state-load-noevents", {_name});
957         return _name;
960 jpcrr.load_state_movie = function(name)
961         local _name, _fname;
962         _name, _fname = toresourcename(name);
963         invokesync("state-load-movie", {_name});
964         return _name;
967 jpcrr.assemble = function()
968         invokesync("pc-assemble");
971 jpcrr.change_authors = function()
972         invokesync("change-authors");
975 jpcrr.ram_dump = function(name, binary)
976         local _name, _fname;
977         _name, _fname = toresourcename(name);
978         if binary then
979                 invokesync("ram-dump-binary", {_name});
980         else
981                 invokesync("ram-dump-text", {_name});
982         end
983         return _name;
986 jpcrr.hud.left_gap = function(f, g)
987         invoke("hud-left-gap", {toString(f), toString(g)});
990 jpcrr.hud.right_gap = function(f, g)
991         invoke("hud-right-gap", {toString(f), toString(g)});
994 jpcrr.hud.top_gap = function(f, g)
995         invoke("hud-top-gap", {toString(f), toString(g)});
998 jpcrr.hud.bottom_gap = function(f, g)
999         invoke("hud-bottom-gap", {toString(f), toString(g)});
1002 jpcrr.hud.white_solid_box = function(f, x, y, w, h)
1003         invoke("hud-white-solid-box", {toString(f), toString(x), toString(y), toString(w), toString(h)});
1006 jpcrr.hud.box = function(f, x, y, w, h, t, lr, lg, lb, la, fr, fg, fb, fa)
1007         invoke("hud-box", {toString(f), toString(x), toString(y), toString(w), toString(h),
1008                 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
1009                 toString(fg), tostring(fb), toString(fa)});
1012 jpcrr.hud.circle = function(f, x, y, r, t, lr, lg, lb, la, fr, fg, fb, fa)
1013         invoke("hud-circle", {toString(f), toString(x), toString(y), toString(r),
1014                 toString(t), toString(lr), toString(lg), toString(lb), toString(la), toString(fr),
1015                 toString(fg), tostring(fb), toString(fa)});
1018 jpcrr.hud.bitmap = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1019         invoke("hud-bitmap", {toString(f), toString(x), toString(y), bmap, toString(lr),
1020                 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
1021                 toString(fa)});
1024 jpcrr.hud.bitmap_binary = function(f, x, y, bmap, lr, lg, lb, la, fr, fg, fb, fa)
1025         invoke("hud-bitmap-binary", {toString(f), toString(x), toString(y), bmap, toString(lr),
1026                 toString(lg), toString(lb), toString(la), toString(fr), toString(fg), tostring(fb),
1027                 toString(fa)});
1030 jpcrr.shutdown_emulator = function()
1031         invokesync("shutdown-emulator", {});
1034 jpcrr.set_pccontrol_pos = function(x, y)
1035         invokesync("pccontrol-setwinpos", {toString(x), toString(y)});
1038 jpcrr.set_luaplugin_pos = function(x, y)
1039         invokesync("luaplugin-setwinpos", {toString(x), toString(y)});
1042 jpcrr.set_pcmonitor_pos = function(x, y)
1043         invokesync("pcmonitor-setwinpos", {toString(x), toString(y)});
1046 jpcrr.set_pcstartstoptest_pos = function(x, y)
1047         invokesync("pcstartstoptest-setwinpos", {toString(x), toString(y)});
1050 jpcrr.set_virtualkeyboard_pos = function(x, y)
1051         invokesync("virtualkeyboard-setwinpos", {toString(x), toString(y)});
1054 jpcrr.exit = function()
1055         invokesync("luaplugin-terminate");
1058 jpcrr.pc_start = function()
1059         invoke("pc-start");
1062 jpcrr.pc_stop = function()
1063         invokesync("pc-stop");
1066 jpcrr.screenshot = function(include_hud)
1067         if include_hud then
1068                 invoke("screenshot-renderbuffer");
1069         else
1070                 invoke("screenshot-vgabuffer");
1071         end
1075 jpcrr.vretrace_start_trap = function(is_on)
1076         if is_on then
1077                 invokesync("trap-vretrace-start-on");
1078         else
1079                 invokesync("trap-vretrace-start-off");
1080         end
1083 jpcrr.vretrace_end_trap = function(is_on)
1084         if is_on then
1085                 invokesync("trap-vretrace-end-on");
1086         else
1087                 invokesync("trap-vretrace-end-off");
1088         end
1091 jpcrr.timed_trap = function(nsecs)
1092         if nsecs then
1093                 invokesync("trap-timed", {toString(nsecs)});
1094         else
1095                 invokesync("trap-timed-disable");
1096         end
1099 jpcrr.write_byte = function(addr, value)
1100         invokesync("memory-write", {toString(addr), toString(value), "1"});
1103 jpcrr.write_word = function(addr, value)
1104         invokesync("memory-write", {toString(addr), toString(value), "2"});
1107 jpcrr.write_dword = function(addr, value)
1108         invokesync("memory-write", {toString(addr), toString(value), "4"});
1111 jpcrr.read_byte = function(addr)
1112         local t = {toString(addr), "1"};
1113         t = invokecall("memory-read", t);
1114         return (t or {})[1];
1117 jpcrr.read_word = function(addr)
1118         local t = {toString(addr), "2"};
1119         t = invokecall("memory-read", t);
1120         return (t or {})[1];
1123 jpcrr.read_dword = function(addr)
1124         local t = {toString(addr), "4"};
1125         t = invokecall("memory-read", t);
1126         return (t or {})[1];
1129 jpcrr.invoke = nil;
1130 jpcrr.invoke_synchronous = nil;
1131 jpcrr.call = null
1133 -- Dofile.
1134 dofile = function(_script)
1135         local chunk, err, indication
1136         chunk, err = loadfile(_script);
1137         if not chunk then
1138                 error("Kernel: Can't load subscript " .. _script .. ": " .. err);
1139         end
1140         return chunk();
1143 local args2 = args;
1144 args = null;
1145 args = {};
1146 for k, v in pairs(args2) do
1147         if (#k > 2 and string.byte(k, 1) == 120 and string.byte(k, 2) == 45) then
1148                 args[string.sub(k, 3)] = v;
1149         end
1151 jpcrr_raw = null;
1154         chunk = null;
1155         loaded, err = pcall(function()
1156                 chunk, err = loadfile(script);
1157                 if not chunk then
1158                         error(err);
1159                 end
1160         end);
1161         if not loaded then
1162                 print("Kernel: Can't load script " .. script .. ": " .. err);
1163                 invoke("luaplugin-terminate");
1164                 while true do end
1165         end
1167         script = null;
1168         indication, err = pcall(chunk);
1169         if not indication then
1170                 print("Kernel: Unprotected error in script: " .. err);
1171                 invoke("luaplugin-terminate");
1172                 while true do end
1173         end