diff options
author | Torne Wuff <torne@wolfpuppy.org.uk> | 2010-01-17 22:15:13 +0000 |
---|---|---|
committer | Torne Wuff <torne@wolfpuppy.org.uk> | 2010-01-17 22:15:13 +0000 |
commit | 7f28c94eda576e3f972fc05468188986f2e45885 (patch) | |
tree | e03b94613028d16855a5d3df0f4853e077931214 /apps/plugins/frotz/files.c | |
parent | 563f2602f471208cb8544a36539a79dcceaad643 (diff) | |
download | rockbox-7f28c94eda576e3f972fc05468188986f2e45885.tar.gz rockbox-7f28c94eda576e3f972fc05468188986f2e45885.zip |
New plugin: frotz, a Z-machine interpreter, for playing interactive fiction.
The interpreter more or less passes all the tests in the z-machine test suite.
It should build for every target except Archos (for which it is disabled).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24267 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/frotz/files.c')
-rw-r--r-- | apps/plugins/frotz/files.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/apps/plugins/frotz/files.c b/apps/plugins/frotz/files.c new file mode 100644 index 0000000000..1baaa4073f --- /dev/null +++ b/apps/plugins/frotz/files.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* files.c - Transscription, recording and playback | ||
2 | * Copyright (c) 1995-1997 Stefan Jokisch | ||
3 | * | ||
4 | * Changes for Rockbox copyright 2009 Torne Wuff | ||
5 | * | ||
6 | * This file is part of Frotz. | ||
7 | * | ||
8 | * Frotz is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * Frotz is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
21 | */ | ||
22 | |||
23 | #include "frotz.h" | ||
24 | |||
25 | extern void set_more_prompts (bool); | ||
26 | |||
27 | extern bool is_terminator (zchar); | ||
28 | |||
29 | extern bool read_yes_or_no (const char *); | ||
30 | |||
31 | char script_name[MAX_PATH]; | ||
32 | char command_name[MAX_PATH]; | ||
33 | |||
34 | #ifdef __MSDOS__ | ||
35 | extern char latin1_to_ibm[]; | ||
36 | #endif | ||
37 | |||
38 | static int script_width = 0; | ||
39 | |||
40 | int sfp = -1; | ||
41 | int rfp = -1; | ||
42 | int pfp = -1; | ||
43 | |||
44 | /* | ||
45 | * script_open | ||
46 | * | ||
47 | * Open the transscript file. 'AMFV' makes this more complicated as it | ||
48 | * turns transscription on/off several times to exclude some text from | ||
49 | * the transscription file. This wasn't a problem for the original V4 | ||
50 | * interpreters which always sent transscription to the printer, but it | ||
51 | * means a problem to modern interpreters that offer to open a new file | ||
52 | * every time transscription is turned on. Our solution is to append to | ||
53 | * the old transscription file in V1 to V4, and to ask for a new file | ||
54 | * name in V5+. | ||
55 | * | ||
56 | */ | ||
57 | |||
58 | void script_open (void) | ||
59 | { | ||
60 | static bool script_valid = FALSE; | ||
61 | |||
62 | char new_name[MAX_PATH]; | ||
63 | |||
64 | h_flags &= ~SCRIPTING_FLAG; | ||
65 | |||
66 | if (h_version >= V5 || !script_valid) { | ||
67 | |||
68 | if (!os_read_file_name (new_name, script_name, FILE_SCRIPT)) | ||
69 | goto done; | ||
70 | |||
71 | strcpy (script_name, new_name); | ||
72 | |||
73 | } | ||
74 | |||
75 | /* Opening in "at" mode doesn't work for script_erase_input... */ | ||
76 | |||
77 | if ((sfp = rb->open (script_name, O_RDWR|O_CREAT)) != -1) { | ||
78 | |||
79 | fseek (sfp, 0, SEEK_END); | ||
80 | |||
81 | h_flags |= SCRIPTING_FLAG; | ||
82 | |||
83 | script_valid = TRUE; | ||
84 | ostream_script = TRUE; | ||
85 | |||
86 | script_width = 0; | ||
87 | |||
88 | } else print_string ("Cannot open file\n"); | ||
89 | |||
90 | done: | ||
91 | |||
92 | SET_WORD (H_FLAGS, h_flags) | ||
93 | |||
94 | }/* script_open */ | ||
95 | |||
96 | /* | ||
97 | * script_close | ||
98 | * | ||
99 | * Stop transscription. | ||
100 | * | ||
101 | */ | ||
102 | |||
103 | void script_close (void) | ||
104 | { | ||
105 | |||
106 | h_flags &= ~SCRIPTING_FLAG; | ||
107 | SET_WORD (H_FLAGS, h_flags) | ||
108 | |||
109 | fclose (sfp); ostream_script = FALSE; | ||
110 | sfp = -1; | ||
111 | |||
112 | }/* script_close */ | ||
113 | |||
114 | /* | ||
115 | * script_new_line | ||
116 | * | ||
117 | * Write a newline to the transscript file. | ||
118 | * | ||
119 | */ | ||
120 | |||
121 | void script_new_line (void) | ||
122 | { | ||
123 | |||
124 | if (fputc ('\n', sfp) == EOF) | ||
125 | script_close (); | ||
126 | |||
127 | script_width = 0; | ||
128 | |||
129 | }/* script_new_line */ | ||
130 | |||
131 | /* | ||
132 | * script_char | ||
133 | * | ||
134 | * Write a single character to the transscript file. | ||
135 | * | ||
136 | */ | ||
137 | |||
138 | void script_char (zchar c) | ||
139 | { | ||
140 | |||
141 | if (c == ZC_INDENT && script_width != 0) | ||
142 | c = ' '; | ||
143 | |||
144 | if (c == ZC_INDENT) | ||
145 | { script_char (' '); script_char (' '); script_char (' '); return; } | ||
146 | if (c == ZC_GAP) | ||
147 | { script_char (' '); script_char (' '); return; } | ||
148 | |||
149 | #ifdef __MSDOS__ | ||
150 | if (c >= ZC_LATIN1_MIN) | ||
151 | c = latin1_to_ibm[c - ZC_LATIN1_MIN]; | ||
152 | #endif | ||
153 | |||
154 | fputc (c, sfp); script_width++; | ||
155 | |||
156 | }/* script_char */ | ||
157 | |||
158 | /* | ||
159 | * script_word | ||
160 | * | ||
161 | * Write a string to the transscript file. | ||
162 | * | ||
163 | */ | ||
164 | |||
165 | void script_word (const zchar *s) | ||
166 | { | ||
167 | int width; | ||
168 | int i; | ||
169 | |||
170 | if (*s == ZC_INDENT && script_width != 0) | ||
171 | script_char (*s++); | ||
172 | |||
173 | for (i = 0, width = 0; s[i] != 0; i++) | ||
174 | |||
175 | if (s[i] == ZC_NEW_STYLE || s[i] == ZC_NEW_FONT) | ||
176 | i++; | ||
177 | else if (s[i] == ZC_GAP) | ||
178 | width += 3; | ||
179 | else if (s[i] == ZC_INDENT) | ||
180 | width += 2; | ||
181 | else | ||
182 | width += 1; | ||
183 | |||
184 | if (f_setup.script_cols != 0 && script_width + width > f_setup.script_cols) { | ||
185 | |||
186 | if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP) | ||
187 | s++; | ||
188 | |||
189 | script_new_line (); | ||
190 | |||
191 | } | ||
192 | |||
193 | for (i = 0; s[i] != 0; i++) | ||
194 | |||
195 | if (s[i] == ZC_NEW_FONT || s[i] == ZC_NEW_STYLE) | ||
196 | i++; | ||
197 | else | ||
198 | script_char (s[i]); | ||
199 | |||
200 | }/* script_word */ | ||
201 | |||
202 | /* | ||
203 | * script_write_input | ||
204 | * | ||
205 | * Send an input line to the transscript file. | ||
206 | * | ||
207 | */ | ||
208 | |||
209 | void script_write_input (const zchar *buf, zchar key) | ||
210 | { | ||
211 | int width; | ||
212 | int i; | ||
213 | |||
214 | for (i = 0, width = 0; buf[i] != 0; i++) | ||
215 | width++; | ||
216 | |||
217 | if (f_setup.script_cols != 0 && script_width + width > f_setup.script_cols) | ||
218 | script_new_line (); | ||
219 | |||
220 | for (i = 0; buf[i] != 0; i++) | ||
221 | script_char (buf[i]); | ||
222 | |||
223 | if (key == ZC_RETURN) | ||
224 | script_new_line (); | ||
225 | |||
226 | }/* script_write_input */ | ||
227 | |||
228 | /* | ||
229 | * script_erase_input | ||
230 | * | ||
231 | * Remove an input line from the transscript file. | ||
232 | * | ||
233 | */ | ||
234 | |||
235 | void script_erase_input (const zchar *buf) | ||
236 | { | ||
237 | int width; | ||
238 | int i; | ||
239 | |||
240 | for (i = 0, width = 0; buf[i] != 0; i++) | ||
241 | width++; | ||
242 | |||
243 | fseek (sfp, -width, SEEK_CUR); script_width -= width; | ||
244 | |||
245 | }/* script_erase_input */ | ||
246 | |||
247 | /* | ||
248 | * script_mssg_on | ||
249 | * | ||
250 | * Start sending a "debugging" message to the transscript file. | ||
251 | * | ||
252 | */ | ||
253 | |||
254 | void script_mssg_on (void) | ||
255 | { | ||
256 | |||
257 | if (script_width != 0) | ||
258 | script_new_line (); | ||
259 | |||
260 | script_char (ZC_INDENT); | ||
261 | |||
262 | }/* script_mssg_on */ | ||
263 | |||
264 | /* | ||
265 | * script_mssg_off | ||
266 | * | ||
267 | * Stop writing a "debugging" message. | ||
268 | * | ||
269 | */ | ||
270 | |||
271 | void script_mssg_off (void) | ||
272 | { | ||
273 | |||
274 | script_new_line (); | ||
275 | |||
276 | }/* script_mssg_off */ | ||
277 | |||
278 | /* | ||
279 | * record_open | ||
280 | * | ||
281 | * Open a file to record the player's input. | ||
282 | * | ||
283 | */ | ||
284 | |||
285 | void record_open (void) | ||
286 | { | ||
287 | char new_name[MAX_PATH]; | ||
288 | |||
289 | if (os_read_file_name (new_name, command_name, FILE_RECORD)) { | ||
290 | |||
291 | strcpy (command_name, new_name); | ||
292 | |||
293 | if ((rfp = rb->open (new_name, O_WRONLY|O_CREAT|O_TRUNC)) != -1) | ||
294 | ostream_record = TRUE; | ||
295 | else | ||
296 | print_string ("Cannot open file\n"); | ||
297 | |||
298 | } | ||
299 | |||
300 | }/* record_open */ | ||
301 | |||
302 | /* | ||
303 | * record_close | ||
304 | * | ||
305 | * Stop recording the player's input. | ||
306 | * | ||
307 | */ | ||
308 | |||
309 | void record_close (void) | ||
310 | { | ||
311 | |||
312 | fclose (rfp); ostream_record = FALSE; | ||
313 | rfp = -1; | ||
314 | |||
315 | }/* record_close */ | ||
316 | |||
317 | /* | ||
318 | * record_code | ||
319 | * | ||
320 | * Helper function for record_char. | ||
321 | * | ||
322 | */ | ||
323 | |||
324 | static void record_code (int c, bool force_encoding) | ||
325 | { | ||
326 | |||
327 | if (force_encoding || c == '[' || c < 0x20 || c > 0x7e) { | ||
328 | |||
329 | int i; | ||
330 | |||
331 | fputc ('[', rfp); | ||
332 | |||
333 | for (i = 10000; i != 0; i /= 10) | ||
334 | if (c >= i || i == 1) | ||
335 | fputc ('0' + (c / i) % 10, rfp); | ||
336 | |||
337 | fputc (']', rfp); | ||
338 | |||
339 | } else fputc (c, rfp); | ||
340 | |||
341 | }/* record_code */ | ||
342 | |||
343 | /* | ||
344 | * record_char | ||
345 | * | ||
346 | * Write a character to the command file. | ||
347 | * | ||
348 | */ | ||
349 | |||
350 | static void record_char (zchar c) | ||
351 | { | ||
352 | |||
353 | if (c != ZC_RETURN) { | ||
354 | if (c < ZC_HKEY_MIN || c > ZC_HKEY_MAX) { | ||
355 | record_code (translate_to_zscii (c), FALSE); | ||
356 | if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) { | ||
357 | record_code (mouse_x, TRUE); | ||
358 | record_code (mouse_y, TRUE); | ||
359 | } | ||
360 | } else record_code (1000 + c - ZC_HKEY_MIN, TRUE); | ||
361 | } | ||
362 | |||
363 | }/* record_char */ | ||
364 | |||
365 | /* | ||
366 | * record_write_key | ||
367 | * | ||
368 | * Copy a keystroke to the command file. | ||
369 | * | ||
370 | */ | ||
371 | |||
372 | void record_write_key (zchar key) | ||
373 | { | ||
374 | |||
375 | record_char (key); | ||
376 | |||
377 | if (fputc ('\n', rfp) == EOF) | ||
378 | record_close (); | ||
379 | |||
380 | }/* record_write_key */ | ||
381 | |||
382 | /* | ||
383 | * record_write_input | ||
384 | * | ||
385 | * Copy a line of input to a command file. | ||
386 | * | ||
387 | */ | ||
388 | |||
389 | void record_write_input (const zchar *buf, zchar key) | ||
390 | { | ||
391 | zchar c; | ||
392 | |||
393 | while ((c = *buf++) != 0) | ||
394 | record_char (c); | ||
395 | |||
396 | record_char (key); | ||
397 | |||
398 | if (fputc ('\n', rfp) == EOF) | ||
399 | record_close (); | ||
400 | |||
401 | }/* record_write_input */ | ||
402 | |||
403 | /* | ||
404 | * replay_open | ||
405 | * | ||
406 | * Open a file of commands for playback. | ||
407 | * | ||
408 | */ | ||
409 | |||
410 | void replay_open (void) | ||
411 | { | ||
412 | char new_name[MAX_PATH]; | ||
413 | |||
414 | if (os_read_file_name (new_name, command_name, FILE_PLAYBACK)) { | ||
415 | |||
416 | strcpy (command_name, new_name); | ||
417 | |||
418 | if ((pfp = rb->open (new_name, O_RDONLY)) != -1) { | ||
419 | |||
420 | set_more_prompts (read_yes_or_no ("Do you want MORE prompts")); | ||
421 | |||
422 | istream_replay = TRUE; | ||
423 | |||
424 | } else print_string ("Cannot open file\n"); | ||
425 | |||
426 | } | ||
427 | |||
428 | }/* replay_open */ | ||
429 | |||
430 | /* | ||
431 | * replay_close | ||
432 | * | ||
433 | * Stop playback of commands. | ||
434 | * | ||
435 | */ | ||
436 | |||
437 | void replay_close (void) | ||
438 | { | ||
439 | |||
440 | set_more_prompts (TRUE); | ||
441 | |||
442 | fclose (pfp); istream_replay = FALSE; | ||
443 | pfp = -1; | ||
444 | |||
445 | }/* replay_close */ | ||
446 | |||
447 | /* | ||
448 | * replay_code | ||
449 | * | ||
450 | * Helper function for replay_key and replay_line. | ||
451 | * | ||
452 | */ | ||
453 | |||
454 | static int replay_code (void) | ||
455 | { | ||
456 | int c; | ||
457 | |||
458 | if ((c = fgetc (pfp)) == '[') { | ||
459 | |||
460 | int c2; | ||
461 | |||
462 | c = 0; | ||
463 | |||
464 | while ((c2 = fgetc (pfp)) != EOF && c2 >= '0' && c2 <= '9') | ||
465 | c = 10 * c + c2 - '0'; | ||
466 | |||
467 | return (c2 == ']') ? c : EOF; | ||
468 | |||
469 | } else return c; | ||
470 | |||
471 | }/* replay_code */ | ||
472 | |||
473 | /* | ||
474 | * replay_char | ||
475 | * | ||
476 | * Read a character from the command file. | ||
477 | * | ||
478 | */ | ||
479 | |||
480 | static zchar replay_char (void) | ||
481 | { | ||
482 | int c; | ||
483 | |||
484 | if ((c = replay_code ()) != EOF) { | ||
485 | |||
486 | if (c != '\n') { | ||
487 | |||
488 | if (c < 1000) { | ||
489 | |||
490 | c = translate_from_zscii (c); | ||
491 | |||
492 | if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) { | ||
493 | mouse_x = replay_code (); | ||
494 | mouse_y = replay_code (); | ||
495 | } | ||
496 | |||
497 | return c; | ||
498 | |||
499 | } else return ZC_HKEY_MIN + c - 1000; | ||
500 | } | ||
501 | |||
502 | ungetc ('\n', pfp); | ||
503 | |||
504 | return ZC_RETURN; | ||
505 | |||
506 | } else return ZC_BAD; | ||
507 | |||
508 | }/* replay_char */ | ||
509 | |||
510 | /* | ||
511 | * replay_read_key | ||
512 | * | ||
513 | * Read a keystroke from a command file. | ||
514 | * | ||
515 | */ | ||
516 | |||
517 | zchar replay_read_key (void) | ||
518 | { | ||
519 | zchar key; | ||
520 | |||
521 | key = replay_char (); | ||
522 | |||
523 | if (fgetc (pfp) != '\n') { | ||
524 | |||
525 | replay_close (); | ||
526 | return ZC_BAD; | ||
527 | |||
528 | } else return key; | ||
529 | |||
530 | }/* replay_read_key */ | ||
531 | |||
532 | /* | ||
533 | * replay_read_input | ||
534 | * | ||
535 | * Read a line of input from a command file. | ||
536 | * | ||
537 | */ | ||
538 | |||
539 | zchar replay_read_input (zchar *buf) | ||
540 | { | ||
541 | zchar c; | ||
542 | |||
543 | for (;;) { | ||
544 | |||
545 | c = replay_char (); | ||
546 | |||
547 | if (c == ZC_BAD || is_terminator (c)) | ||
548 | break; | ||
549 | |||
550 | *buf++ = c; | ||
551 | |||
552 | } | ||
553 | |||
554 | *buf = 0; | ||
555 | |||
556 | if (fgetc (pfp) != '\n') { | ||
557 | |||
558 | replay_close (); | ||
559 | return ZC_BAD; | ||
560 | |||
561 | } else return c; | ||
562 | |||
563 | }/* replay_read_input */ | ||