rockbox/apps/plugins/frotz/files.c
Torne Wuff 7f28c94eda 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
2010-01-17 22:15:13 +00:00

563 lines
9 KiB
C

/* files.c - Transscription, recording and playback
* Copyright (c) 1995-1997 Stefan Jokisch
*
* Changes for Rockbox copyright 2009 Torne Wuff
*
* This file is part of Frotz.
*
* Frotz is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Frotz is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "frotz.h"
extern void set_more_prompts (bool);
extern bool is_terminator (zchar);
extern bool read_yes_or_no (const char *);
char script_name[MAX_PATH];
char command_name[MAX_PATH];
#ifdef __MSDOS__
extern char latin1_to_ibm[];
#endif
static int script_width = 0;
int sfp = -1;
int rfp = -1;
int pfp = -1;
/*
* script_open
*
* Open the transscript file. 'AMFV' makes this more complicated as it
* turns transscription on/off several times to exclude some text from
* the transscription file. This wasn't a problem for the original V4
* interpreters which always sent transscription to the printer, but it
* means a problem to modern interpreters that offer to open a new file
* every time transscription is turned on. Our solution is to append to
* the old transscription file in V1 to V4, and to ask for a new file
* name in V5+.
*
*/
void script_open (void)
{
static bool script_valid = FALSE;
char new_name[MAX_PATH];
h_flags &= ~SCRIPTING_FLAG;
if (h_version >= V5 || !script_valid) {
if (!os_read_file_name (new_name, script_name, FILE_SCRIPT))
goto done;
strcpy (script_name, new_name);
}
/* Opening in "at" mode doesn't work for script_erase_input... */
if ((sfp = rb->open (script_name, O_RDWR|O_CREAT)) != -1) {
fseek (sfp, 0, SEEK_END);
h_flags |= SCRIPTING_FLAG;
script_valid = TRUE;
ostream_script = TRUE;
script_width = 0;
} else print_string ("Cannot open file\n");
done:
SET_WORD (H_FLAGS, h_flags)
}/* script_open */
/*
* script_close
*
* Stop transscription.
*
*/
void script_close (void)
{
h_flags &= ~SCRIPTING_FLAG;
SET_WORD (H_FLAGS, h_flags)
fclose (sfp); ostream_script = FALSE;
sfp = -1;
}/* script_close */
/*
* script_new_line
*
* Write a newline to the transscript file.
*
*/
void script_new_line (void)
{
if (fputc ('\n', sfp) == EOF)
script_close ();
script_width = 0;
}/* script_new_line */
/*
* script_char
*
* Write a single character to the transscript file.
*
*/
void script_char (zchar c)
{
if (c == ZC_INDENT && script_width != 0)
c = ' ';
if (c == ZC_INDENT)
{ script_char (' '); script_char (' '); script_char (' '); return; }
if (c == ZC_GAP)
{ script_char (' '); script_char (' '); return; }
#ifdef __MSDOS__
if (c >= ZC_LATIN1_MIN)
c = latin1_to_ibm[c - ZC_LATIN1_MIN];
#endif
fputc (c, sfp); script_width++;
}/* script_char */
/*
* script_word
*
* Write a string to the transscript file.
*
*/
void script_word (const zchar *s)
{
int width;
int i;
if (*s == ZC_INDENT && script_width != 0)
script_char (*s++);
for (i = 0, width = 0; s[i] != 0; i++)
if (s[i] == ZC_NEW_STYLE || s[i] == ZC_NEW_FONT)
i++;
else if (s[i] == ZC_GAP)
width += 3;
else if (s[i] == ZC_INDENT)
width += 2;
else
width += 1;
if (f_setup.script_cols != 0 && script_width + width > f_setup.script_cols) {
if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
s++;
script_new_line ();
}
for (i = 0; s[i] != 0; i++)
if (s[i] == ZC_NEW_FONT || s[i] == ZC_NEW_STYLE)
i++;
else
script_char (s[i]);
}/* script_word */
/*
* script_write_input
*
* Send an input line to the transscript file.
*
*/
void script_write_input (const zchar *buf, zchar key)
{
int width;
int i;
for (i = 0, width = 0; buf[i] != 0; i++)
width++;
if (f_setup.script_cols != 0 && script_width + width > f_setup.script_cols)
script_new_line ();
for (i = 0; buf[i] != 0; i++)
script_char (buf[i]);
if (key == ZC_RETURN)
script_new_line ();
}/* script_write_input */
/*
* script_erase_input
*
* Remove an input line from the transscript file.
*
*/
void script_erase_input (const zchar *buf)
{
int width;
int i;
for (i = 0, width = 0; buf[i] != 0; i++)
width++;
fseek (sfp, -width, SEEK_CUR); script_width -= width;
}/* script_erase_input */
/*
* script_mssg_on
*
* Start sending a "debugging" message to the transscript file.
*
*/
void script_mssg_on (void)
{
if (script_width != 0)
script_new_line ();
script_char (ZC_INDENT);
}/* script_mssg_on */
/*
* script_mssg_off
*
* Stop writing a "debugging" message.
*
*/
void script_mssg_off (void)
{
script_new_line ();
}/* script_mssg_off */
/*
* record_open
*
* Open a file to record the player's input.
*
*/
void record_open (void)
{
char new_name[MAX_PATH];
if (os_read_file_name (new_name, command_name, FILE_RECORD)) {
strcpy (command_name, new_name);
if ((rfp = rb->open (new_name, O_WRONLY|O_CREAT|O_TRUNC)) != -1)
ostream_record = TRUE;
else
print_string ("Cannot open file\n");
}
}/* record_open */
/*
* record_close
*
* Stop recording the player's input.
*
*/
void record_close (void)
{
fclose (rfp); ostream_record = FALSE;
rfp = -1;
}/* record_close */
/*
* record_code
*
* Helper function for record_char.
*
*/
static void record_code (int c, bool force_encoding)
{
if (force_encoding || c == '[' || c < 0x20 || c > 0x7e) {
int i;
fputc ('[', rfp);
for (i = 10000; i != 0; i /= 10)
if (c >= i || i == 1)
fputc ('0' + (c / i) % 10, rfp);
fputc (']', rfp);
} else fputc (c, rfp);
}/* record_code */
/*
* record_char
*
* Write a character to the command file.
*
*/
static void record_char (zchar c)
{
if (c != ZC_RETURN) {
if (c < ZC_HKEY_MIN || c > ZC_HKEY_MAX) {
record_code (translate_to_zscii (c), FALSE);
if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
record_code (mouse_x, TRUE);
record_code (mouse_y, TRUE);
}
} else record_code (1000 + c - ZC_HKEY_MIN, TRUE);
}
}/* record_char */
/*
* record_write_key
*
* Copy a keystroke to the command file.
*
*/
void record_write_key (zchar key)
{
record_char (key);
if (fputc ('\n', rfp) == EOF)
record_close ();
}/* record_write_key */
/*
* record_write_input
*
* Copy a line of input to a command file.
*
*/
void record_write_input (const zchar *buf, zchar key)
{
zchar c;
while ((c = *buf++) != 0)
record_char (c);
record_char (key);
if (fputc ('\n', rfp) == EOF)
record_close ();
}/* record_write_input */
/*
* replay_open
*
* Open a file of commands for playback.
*
*/
void replay_open (void)
{
char new_name[MAX_PATH];
if (os_read_file_name (new_name, command_name, FILE_PLAYBACK)) {
strcpy (command_name, new_name);
if ((pfp = rb->open (new_name, O_RDONLY)) != -1) {
set_more_prompts (read_yes_or_no ("Do you want MORE prompts"));
istream_replay = TRUE;
} else print_string ("Cannot open file\n");
}
}/* replay_open */
/*
* replay_close
*
* Stop playback of commands.
*
*/
void replay_close (void)
{
set_more_prompts (TRUE);
fclose (pfp); istream_replay = FALSE;
pfp = -1;
}/* replay_close */
/*
* replay_code
*
* Helper function for replay_key and replay_line.
*
*/
static int replay_code (void)
{
int c;
if ((c = fgetc (pfp)) == '[') {
int c2;
c = 0;
while ((c2 = fgetc (pfp)) != EOF && c2 >= '0' && c2 <= '9')
c = 10 * c + c2 - '0';
return (c2 == ']') ? c : EOF;
} else return c;
}/* replay_code */
/*
* replay_char
*
* Read a character from the command file.
*
*/
static zchar replay_char (void)
{
int c;
if ((c = replay_code ()) != EOF) {
if (c != '\n') {
if (c < 1000) {
c = translate_from_zscii (c);
if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
mouse_x = replay_code ();
mouse_y = replay_code ();
}
return c;
} else return ZC_HKEY_MIN + c - 1000;
}
ungetc ('\n', pfp);
return ZC_RETURN;
} else return ZC_BAD;
}/* replay_char */
/*
* replay_read_key
*
* Read a keystroke from a command file.
*
*/
zchar replay_read_key (void)
{
zchar key;
key = replay_char ();
if (fgetc (pfp) != '\n') {
replay_close ();
return ZC_BAD;
} else return key;
}/* replay_read_key */
/*
* replay_read_input
*
* Read a line of input from a command file.
*
*/
zchar replay_read_input (zchar *buf)
{
zchar c;
for (;;) {
c = replay_char ();
if (c == ZC_BAD || is_terminator (c))
break;
*buf++ = c;
}
*buf = 0;
if (fgetc (pfp) != '\n') {
replay_close ();
return ZC_BAD;
} else return c;
}/* replay_read_input */