1 /* $Header$ */ 2 3 /* 4 * Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved. 5 * 6 * Please see the accompanying license file, LICENSE.TXT, for information 7 * on using and copying this software. 8 */ 9 /* 10 Name 11 vmmain.h - main entrypoint to run a T3 image file 12 Function 13 14 Notes 15 16 Modified 17 10/07/99 MJRoberts - Creation 18 */ 19 20 #ifndef VMMAIN_H 21 #define VMMAIN_H 22 23 #include "vmglob.h" 24 25 /* 26 * Parse a command line to determine the name of the game file specified by 27 * the arguments. If we can find a game file specification, we'll fill in 28 * 'buf' with the filename and return true; if there's no file name 29 * specified, we'll return false. 30 * 31 * Note that our parsing will work for TADS 2 or TADS 3 interpreter command 32 * lines, so this routine can be used to extract the filename from an 33 * ambiguous command line in order to check the file for its type and 34 * thereby resolve which interpreter to use. 35 * 36 * Note that the filename might not come directly from the command 37 * arguments, since it might be implied. If there's no game file directly 38 * specified, but there is an explicit "-r" option to restore a saved game, 39 * we'll pull the game filename out of the saved game file if possible. 40 * Saved game files in both TADS 2 and TADS 3 can store the original game 41 * file name that was being executed at the time the game was saved. 42 */ 43 int vm_get_game_arg(int argc, const char *const *argv, 44 char *buf, size_t buflen); 45 46 /* 47 * Given a game file argument, determine which engine (TADS 2 or TADS 3) 48 * should be used to run the game. 49 * 50 * We'll first check to see if the given file exists. If it does, we'll 51 * read header information from the file to try to identify the game. If 52 * the file does not exist, we will proceed to check default suffixes, if 53 * the suffix arguments are non-null. 54 * 55 * If defexts is not null, it gives an array of default filename suffix 56 * strings, suitable for use with os_defext(). When the name as given 57 * doesn't refer to an existing file, we'll try looking for files with 58 * these suffixes, one at a time. 59 * 60 * Returns one of the VM_GGT_xxx codes. 61 * 62 * If the return value is 2 or 3, we'll fill in the actual_filename buffer 63 * with the full name of the file; if we added a default suffix, the 64 * suffix will be included in this result. 65 */ 66 int vm_get_game_type(const char *filename, 67 char *actual_filename, 68 size_t actual_filename_buffer_length, 69 const char *const *defexts, size_t defext_count); 70 71 /* 72 * Returns codes for vm_get_game_type() 73 */ 74 75 /* game type is TADS 2 */ 76 #define VM_GGT_TADS2 2 77 78 /* game type is TADS 3 */ 79 #define VM_GGT_TADS3 3 80 81 /* game file not found (even after trying default extensions) */ 82 #define VM_GGT_NOT_FOUND (-1) 83 84 /* game file exists but isn't a valid tads 2 or tads 3 game */ 85 #define VM_GGT_INVALID (-2) 86 87 /* 88 * ambiguous filename - the exact filename doesn't exist, and more than 89 * one default suffix version exists 90 */ 91 #define VM_GGT_AMBIG (-3) 92 93 /* 94 * determine if a VM_GGT_xxx code refers to a valid engine version: 95 * returns true if the code is an engine version, false if the code is an 96 * error indication 97 */ 98 #define vm_ggt_is_valid(code) ((code) > 0) 99 100 101 /* 102 * Execute an image file. We'll return zero on success, or a VM error code 103 * on failure. If an error occurs, we'll fill in 'errbuf' with the text of 104 * a message describing the problem. 105 * 106 * If 'load_from_exe' is true, the image filename given is actually the 107 * name of the native executable file that we're running, and we should 108 * load the image file that's attached to the native executable file via 109 * the system-specific os_exeseek() mechanism. 110 * 111 * If 'script_file' is not null, we'll read console input from the given 112 * file. If 'log_file' is not null, we'll log console output to the given 113 * file. If 'cmd_log_file' is not null, we'll log each line we read from 114 * the console to the given command logging file. 115 * 116 * 'charset' optionally selects a character set to use for text displayed 117 * to or read from the user interface. If this is null, we'll use the 118 * current system character set as indicated by the osifc layer. 'charset' 119 * should usually be null unless explicitly specified by the user. 120 */ 121 int vm_run_image(class CVmMainClientIfc *clientifc, 122 const char *image_file_name, 123 class CVmHostIfc *hostifc, 124 const char *const *prog_argv, int prog_argc, 125 const char *script_file, const char *log_file, 126 const char *cmd_log_file, 127 int load_from_exe, int show_banner, const char *charset, 128 const char *saved_state, const char *res_dir); 129 130 /* 131 * Execute an image file using argc/argv conventions. We'll parse the 132 * command line and invoke the program. 133 * 134 * The 'executable_name' is the name of the host program; this is used to 135 * prepare "usage" messages. 136 * 137 * If 'defext' is true, we'll try adding a default extension ("t3", 138 * formerly "t3x") to the name of the image file we find if the given 139 * filename doesn't exist. We'll always check to see if the file exists 140 * with the exact given name before we do this, so that we don't add an 141 * extension where none is needed. If the caller doesn't want us to try 142 * adding an extension at all, pass in 'defext' as false. 143 * 144 * If 'test_mode' is true, we'll make some small changes to the program 145 * invocation protocol appropriate to running system tests. In 146 * particular, we'll build the program argument list with only the root 147 * name of the image file, not the full path - this allows the program to 148 * display the argument list without any dependencies on local path name 149 * conventions or the local directory structure, allowing for more easily 150 * portable test scripts. 151 * 152 * If 'hostifc' is null, we'll provide our own default interface. The 153 * caller can provide a custom host interface by passing in a non-null 154 * 'hostifc' value. 155 */ 156 int vm_run_image_main(class CVmMainClientIfc *clientifc, 157 const char *executable_name, 158 int argc, char **argv, int defext, int test_mode, 159 class CVmHostIfc *hostifc); 160 161 /* 162 * VM Main client services interface. Callers of the vm_run_image 163 * functions must provide an implementation of this interface. 164 */ 165 class CVmMainClientIfc 166 { 167 public: 168 /* 169 * Set "plain" mode. This should set the console to plain ASCII output 170 * mode, if appropriate. Note that this can be called before 171 * client_init(), and no globals are generally present at this point. 172 * 173 * In most cases, this can make a call to os_plain() to set the 174 * OS-level console to plain mode. Non-console applications generally 175 * need not do anything here at all. 176 */ 177 virtual void set_plain_mode() = 0; 178 179 /* 180 * Create the main system console, if desired. This is called during 181 * VM initialization, so it is called prior to client_init(). Returns 182 * the main console object, if desired. If no main console is desired 183 * for this application, return null. 184 */ 185 virtual class CVmConsoleMain *create_console( 186 struct vm_globals *globals) = 0; 187 188 /* 189 * Delete the console, if we created one. This is called during VM 190 * termination, so it's called after client_terminate(). If 191 * create_console() doesn't create a console, this routine need do 192 * nothing. 193 */ 194 virtual void delete_console(struct vm_globals *globals, 195 class CVmConsoleMain *console) = 0; 196 197 /* 198 * Initialization - we'll invoke this immediately after initializing 199 * the VM (via vm_initialize), so the client can perform any global 200 * initialization desired. The globals are valid at this point because 201 * we have completed VM initialization. 202 * 203 * If script_file is non-null, it gives the name of a file to use as 204 * the source of console input. The client implementation should set 205 * up accordingly; if the standard console (G_console) is being used, 206 * the client can simply use G_console->open_script_file() to set up 207 * scripting. 208 * 209 * If log_file is non-null, it gives the name of a file to use to log 210 * console output. The client shoudl set up logging; if the standard 211 * console if being used, G_console->open_log_file() will do the trick. 212 * 213 * If cmd_log_file is non-null, it gives the name of a file to use to 214 * log commands read from the input (i.e., only command input should be 215 * logged, not other console output). If the standard console is being 216 * used, G_console->open_command_log() will set things up properly. 217 * 218 * If banner_str is non-null, it gives a VM banner string that should 219 * be displayed to the user. If the standard console is being used, 220 * this can be displayed using G_console->format_text(). 221 * 222 * The parameters (script_file, log_file, cmd_log_file, and the 223 * presence or absence of banner_str) are taken from the startup 224 * parameters. For a command-line version, for example, these come 225 * from command line options. So, these are necessarily passed down in 226 * some form from the client to begin with; so a client that never 227 * passes these to vm_run_image() or vm_run_image_main() doesn't need 228 * to handle these parameters at all here. 229 */ 230 virtual void client_init(struct vm_globals *globals, 231 const char *script_file, 232 const char *log_file, 233 const char *cmd_log_file, 234 const char *banner_str) = 0; 235 236 /* 237 * Termination - we'll invoke this immediately before terminating the 238 * VM (via vm_terminate). Globals are still valid at this point, but 239 * will be destroyed after this returns. 240 */ 241 virtual void client_terminate(struct vm_globals *globals) = 0; 242 243 /* 244 * pre-execution notification - we'll invoke this function just before 245 * starting execution in the loaded image 246 */ 247 virtual void pre_exec(struct vm_globals *globals) = 0; 248 249 /* 250 * terminate - we'll invoke this just after execution in the loaded 251 * image terminates 252 */ 253 virtual void post_exec(struct vm_globals *globals) = 0; 254 255 /* 256 * Terminate with error - we'll invoke this upon catching an 257 * exception that the image file doesn't handle and which thus 258 * terminates execution. Note that if this is called, post_exec() 259 * will not be called; however, if post_exec() itself throws an 260 * exception, we'll invoke this routine. 261 */ 262 virtual void post_exec_err(struct vm_globals *globals) = 0; 263 264 /* 265 * Display an error message. We'll call this with a complete error 266 * message to display. Note that we won't add a newline at the end of 267 * the message, so if the message is to be displayed on a stdio-style 268 * terminal, this routine should display a newline after the message. 269 * 270 * If the implementation normally writes the text to the main output 271 * console (G_console), it must take into the account the possibility 272 * that we have not opened a system console at all (i.e., G_console 273 * could be null), or have not allocated any globals at all (i.e., 274 * 'globals' could be null). 275 * 276 * If 'add_blank_line' is true, the implementation should add a blank 277 * line after the error, if appropriate for the display device. If 278 * we're displaying the message in an alert box on a GUI, for example, 279 * this can be ignored. 280 */ 281 virtual void display_error(struct vm_globals *globals, 282 const char *msg, int add_blank_line) = 0; 283 }; 284 285 #endif /* VMMAIN_H */ 286 287