cfad47cfa3/src/frobtadsapp.cc

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* FrobTadsApplication class implementation.
2
 */
3
#include "common.h"
4
5
#include <stdio.h>
6
#include <string.h>
7
#include <stdlib.h>
8
#include <signal.h>
9
10
#include "os.h"
11
#include "trd.h"
12
#include "t3std.h"
13
#include "vmmain.h"
14
#include "vmvsn.h"
15
#include "vmmaincn.h"
16
#include "vmhostsi.h"
17
extern "C"
18
{
19
#include "osgen.h"
20
}
21
22
#include "frobtadsapp.h"
23
#include "frobappctx.h"
24
25
26
FrobTadsApplication* globalApp;
27
28
29
/* Wee need a signal handler to handle window resizes when running
30
 * inside a terminal.
31
 */
32
RETSIGTYPE winResizeHandler( int )
33
{
34
	// Re-initialize the screen.
35
	globalApp->resizeEvent();
36
37
	// Change the corresponding global variables that TADS uses to
38
	// tell the size.
39
	G_oss_screen_width = globalApp->width();
40
	G_oss_screen_height = globalApp->height();
41
42
	// Tell TADS that the size just changed.
43
	osssb_on_resize_screen();
44
	// Flush the screen just in case.
45
	globalApp->flush();
46
47
	// Restore the timeout.
48
	// FIXME: This resets the timeout to its initial
49
	// value.  We want to actually set it to the
50
	// remaining timeout.
51
	//globalApp->fGameWindow->setTimeout(0);
52
53
	// Not sure why, but on some systems the handler has to be
54
	// installed over and over again after the signal is handled.
55
#ifdef HAVE_SIGWINCH
56
	signal(SIGWINCH, winResizeHandler);
57
#endif
58
}
59
60
61
FrobTadsApplication::FrobTadsApplication( const FrobOptions& opts )
62
: options(opts), fRemainingTimeout(0), fColorsEnabled(false)
63
{
64
	// Initialize the global pointer to us.
65
	globalApp = this;
66
67
	// Install our window-resize signal handler.
68
#ifdef HAVE_SIGWINCH
69
	signal(SIGWINCH, winResizeHandler);
70
#endif
71
}
72
73
74
int
75
FrobTadsApplication::fRunTads2( char* filename )
76
{
77
	// Create the Tads 2 application container context (appctx).  We
78
	// make it static for no other reason than automatic null
79
	// initialization of the fields (C++ guarantees that); unused
80
	// fields *must* be 0, or else the VM would crash.
81
	static appctxdef appctx;
82
83
	// Set the file I/O safety level callback.
84
	appctx.get_io_safety_level = getIoSafetyLevel;
85
86
	// trdmain() requires argc/argv style arguments.  We create some
87
	// to make it happy.
88
	char argv0[] = "frob";
89
	char* argv[2] = {argv0, filename};
90
91
	// Run the Tads 2 VM.
92
	char savExt[] = "sav";
93
	int vmRet = trdmain(2, argv, &appctx, savExt);
94
95
	return vmRet;
96
}
97
98
99
int
100
FrobTadsApplication::fRunTads3( char* filename )
101
{
102
	// Create the Tads 3 host and client services interfaces.
103
	CVmMainClientConsole clientifc;
104
	CVmHostIfc* hostifc = new CVmHostIfcStdio("");
105
106
	// Set the file I/O safety level.
107
	hostifc->set_io_safety(this->options.safetyLevel);
108
109
	// Run the Tads 3 VM.
110
	int vmRet = vm_run_image(&clientifc, filename, hostifc, 0, 0, 0, false, 0, 0, false, false, 0, 0, 0, 0);
111
112
	delete hostifc;
113
	return vmRet;
114
}
115
116
117
int
118
FrobTadsApplication::runTads( const char* filename, int vm )
119
{
120
	// We might strip the path from the filename later, in case we
121
	// change the current directory.
122
	size_t filenameLen = strlen(filename);
123
	char* finalFilenamePtr;
124
	char* finalFilename = new char[filenameLen + 1];
125
	strcpy(finalFilename, filename);
126
	finalFilenamePtr = finalFilename;
127
128
	// We'll try setting the current directory to the game's
129
	// directory (if the user didn't tell us not to).
130
	if (this->options.changeDir) {
131
		char* gameDirBuf = new char[filenameLen + 1];
132
		gameDirBuf[0] = '\0'; // Paranoia.
133
		os_get_path_name(gameDirBuf, filenameLen, filename);
134
		// Try changing the current directory.
135
		if (this->changeDirectory(gameDirBuf)) {
136
			// Success.  Since we changed the current
137
			// directory, we must adapt the filename by
138
			// stripping it from its path.  For this
139
			// purpose, we'll just store the position of the
140
			// filename's first character.
141
			finalFilenamePtr = os_get_root_name(finalFilename);
142
		}
143
		// Done with the directory-name buffer.
144
		delete[] gameDirBuf;
145
	}
146
147
	// Initialize the screen.
148
	this->init();
149
150
	// The osgen layer uses these global variables to determine the
151
	// size of the screen; set them to the width and height of our
152
	// game window.
153
	G_oss_screen_width = this->width();
154
	G_oss_screen_height = this->height();
155
156
	// Initialize the osgen scrollback buffer.
157
	osssbini(this->options.scrollBufSize);
158
159
	// A kludge to circumvent a curses color problem; display one
160
	// character in reverse video then one in normal colors.  This
161
	// avoids the problem where the first block of text is shown in
162
	// wrong colors.
163
	int tmpColor = ossgetcolor(OSGEN_COLOR_STATUSLINE, OSGEN_COLOR_STATUSBG, 0, 0);
164
	ossdsp(0, 0, tmpColor, " ");
165
	globalApp->flush();
166
	tmpColor = ossgetcolor(OSGEN_COLOR_TEXT, OSGEN_COLOR_TEXTBG, 0, 0);
167
	ossdsp(0, 0, tmpColor, " ");
168
	globalApp->flush();
169
170
	// Run the VM.
171
	int vmRet = vm == 0 ? this->fRunTads2(finalFilenamePtr) : this->fRunTads3(finalFilenamePtr);
172
173
	// Done with the filename.
174
	delete[] finalFilename;
175
176
	// Pause.
177
	os_expause();
178
179
	// Delete the scrollback buffer.
180
	osssbdel();
181
182
	// Return the VM's exit code.
183
	return vmRet;
184
}
185
186
187
/* We implement changeDirectory() as a wrapper around chdir() or
188
 * SetCurrentDirectory(); whichever is available.  The former is in
189
 * <unistd.h>, the latter in <windows.h>.  If the system lacks both,
190
 * we'll always return false to indicate failure.
191
 */
192
#ifdef HAVE_CHDIR
193
#include <unistd.h>
194
#endif
195
#ifdef HAVE_SETCURRENTDIRECTORY
196
#include <windows.h>
197
#endif
198
bool
199
FrobTadsApplication::changeDirectory( const char* dir )
200
{
201
#ifdef HAVE_CHDIR
202
	if (chdir(dir) == 0) return true;
203
	return false;
204
#else
205
#ifdef HAVE_SETCURRENTDIRECTORY
206
	return SetCurrentDirectory(dir);
207
#else
208
	return false;
209
#endif
210
#endif
211
}