/* * initialize */ CVmHostIfcStdio::CVmHostIfcStdio(const char *argv0) { char buf[OSFNMAX]; /* remember the program's argv[0], in case we need it later */ argv0_ = lib_copy_str(argv0); /* * Create the resource loader for system resources (character mapping * files, etc) in the same directory as the executable. */ os_get_special_path(buf, sizeof(buf), argv0, OS_GSP_T3_RES); sys_res_loader_ = new CResLoader(buf); /* set the executable filename in the loader, if available */ if (os_get_exe_filename(buf, sizeof(buf), argv0)) sys_res_loader_->set_exe_filename(buf); /* * the default safety level allows reading and writing to the current * directory only */ io_safety_read_ = VM_IO_SAFETY_READWRITE_CUR; io_safety_write_ = VM_IO_SAFETY_READWRITE_CUR; net_client_safety_ = VM_NET_SAFETY_LOCALHOST; net_server_safety_ = VM_NET_SAFETY_LOCALHOST; }
/* * Main Entrypoint for command-line invocations. For simplicity, a * normal C main() or equivalent entrypoint can invoke this routine * directly, using the usual argc/argv conventions. * * Returns a status code suitable for use with exit(): OSEXSUCC if we * successfully loaded and ran an executable, OSEXFAIL on failure. If * an error occurs, we'll fill in 'errbuf' with a message describing the * problem. */ int vm_run_image_main(CVmMainClientIfc *clientifc, const char *executable_name, int argc, char **argv, int defext, int test_mode, CVmHostIfc *hostifc) { int curarg; char image_file_name[OSFNMAX]; int stat; const char *script_file; int script_quiet = TRUE; const char *log_file; const char *cmd_log_file; const char *res_dir; int load_from_exe; int show_banner; int found_image; int hide_usage; int usage_err; const char *charset; const char *log_charset; char *saved_state; /* we haven't found an image file yet */ found_image = FALSE; /* presume we'll show usage on error */ hide_usage = FALSE; /* presume there will be no usage error */ usage_err = FALSE; /* presume we won't have any console input/output files */ script_file = 0; log_file = 0; cmd_log_file = 0; /* presume we'll use the default OS character sets */ charset = 0; log_charset = 0; /* presume we won't show the banner */ show_banner = FALSE; /* presume we won't load from the .exe file */ load_from_exe = FALSE; /* check to see if we can load from the .exe file */ { osfildef *fp; /* look for an image file attached to the executable */ fp = os_exeseek(argv[0], "TGAM"); if (fp != 0) { /* close the file */ osfcls(fp); /* note that we want to load from the executable */ load_from_exe = TRUE; } } /* presume we won't restore a saved state file */ saved_state = 0; /* presume we won't have a resource directory specified */ res_dir = 0; /* scan options */ for (curarg = 1 ; curarg < argc && argv[curarg][0] == '-' ; ++curarg) { /* * if the argument is just '-', it means we're explicitly leaving * the image filename blank and skipping to the arguments to the VM * program itself */ if (argv[curarg][1] == '\0') break; /* check the argument */ switch(argv[curarg][1]) { case 'b': if (strcmp(argv[curarg], "-banner") == 0) { /* make a note to show the banner */ show_banner = TRUE; } else goto opt_error; break; case 'c': if (strcmp(argv[curarg], "-cs") == 0) { ++curarg; if (curarg < argc) charset = argv[curarg]; else goto opt_error; } else if (strcmp(argv[curarg], "-csl") == 0) { ++curarg; if (curarg < argc) log_charset = argv[curarg]; else goto opt_error; } else goto opt_error; break; case 'n': if (strcmp(argv[curarg], "-nobanner") == 0) { /* make a note not to show the banner */ show_banner = FALSE; } else goto opt_error; break; case 's': /* file safety level - check the range */ if (argv[curarg][2] < '0' || argv[curarg][2] > '4' || argv[curarg][3] != '\0') { /* invalid level */ goto opt_error; } else { /* set the level in the host application */ hostifc->set_io_safety(argv[curarg][2] - '0'); } break; case 'i': case 'I': /* * read from a script file (little 'i' reads silently, big 'I' * echoes the log as it goes) - the next argument, or the * remainder of this argument, is the filename */ script_quiet = (argv[curarg][1] == 'i'); script_file = get_opt_arg(argc, argv, &curarg, 2); if (script_file == 0) goto opt_error; break; case 'l': /* log output to file */ log_file = get_opt_arg(argc, argv, &curarg, 2); if (log_file == 0) goto opt_error; break; case 'o': /* log commands to file */ cmd_log_file = get_opt_arg(argc, argv, &curarg, 2); if (cmd_log_file == 0) goto opt_error; break; case 'p': /* check what follows */ if (strcmp(argv[curarg], "-plain") == 0) { /* tell the client to set plain ASCII mode */ clientifc->set_plain_mode(); break; } else goto opt_error; break; case 'r': /* get the name of the saved state file to restore */ saved_state = get_opt_arg(argc, argv, &curarg, 2); if (saved_state == 0) goto opt_error; break; case 'R': /* note the resource root directory */ res_dir = get_opt_arg(argc, argv, &curarg, 2); if (res_dir == 0) goto opt_error; break; default: opt_error: /* discard remaining arguments */ curarg = argc; /* note the error */ usage_err = TRUE; break; } } /* * If there was no usage error so far, but we don't have an image * filename argument, try to find the image file some other way. If we * found an image file embedded in the executable, don't even bother * looking for an image-file argument - we can only run the embedded * image in this case. */ if (usage_err) { /* there was a usage error - don't bother looking for an image file */ } else if (!load_from_exe && curarg + 1 <= argc && strcmp(argv[curarg], "-") != 0) { /* the last argument is the image file name */ strcpy(image_file_name, argv[curarg]); found_image = TRUE; /* * If the given filename exists, use it as-is; otherwise, if * we're allowed to add an extension, try applying a default * extension of "t3" (formerly "t3x") to the given name. */ if (defext && osfacc(image_file_name)) { /* the given name doesn't exist - try a default extension */ os_defext(image_file_name, "t3"); /* formerly "t3x" */ } } else { /* * if we're loading from the executable, try using the executable * filename as the image file */ if (load_from_exe && os_get_exe_filename(image_file_name, sizeof(image_file_name), argv[0])) found_image = TRUE; /* * If we still haven't found an image file, try to get the image * file from the saved state file, if one was specified. Don't * attempt this if we're loading the image from the executable, as * we don't want to allow running a different image file in that * case. */ if (!load_from_exe && !found_image && saved_state != 0) { osfildef *save_fp; /* open the saved state file */ save_fp = osfoprb(saved_state, OSFTT3SAV); if (save_fp != 0) { /* get the name of the image file */ if (CVmSaveFile::restore_get_image( save_fp, image_file_name, sizeof(image_file_name)) == 0) { /* we successfully obtained the filename */ found_image = TRUE; } /* close the file */ osfcls(save_fp); } } /* * if we haven't found the image, and the host system provides a * way of asking the user for a filename, try that */ if (!load_from_exe && !found_image) { /* ask the host system for a game name */ switch (hostifc->get_image_name(image_file_name, sizeof(image_file_name))) { case VMHOST_GIN_IGNORED: /* no effect - we have no new information */ break; case VMHOST_GIN_CANCEL: /* * the user cancelled the dialog - we don't have a * filename, but we also don't want to show usage, since * the user chose not to proceed */ hide_usage = TRUE; break; case VMHOST_GIN_ERROR: /* * an error occurred showing the dialog - there's not * much we can do except show the usage message */ break; case VMHOST_GIN_SUCCESS: /* that was successful - we have an image file now */ found_image = TRUE; break; } } } /* * if we don't have an image file name by this point, we can't * proceed - show the usage message and terminate */ if (usage_err || !found_image) { char buf[OSFNMAX + 1024]; /* show the usage message if allowed */ if (load_from_exe && !usage_err) { sprintf(buf, "An error occurred loading the T3 VM program from " "the embedded data file. This application executable " "file might be corrupted.\n"); /* display the message */ clientifc->display_error(0, buf, FALSE); } else if (!hide_usage) { /* build the usage message */ sprintf(buf, "%s\n" "usage: %s [options] %sarguments]\n" "options:\n" " -banner - show the version/copyright banner\n" " -cs xxx - use character set 'xxx' for keyboard " "and display\n" " -csl xxx - use character set 'xxx' for log files\n" " -i file - read command input from file (quiet mode)\n" " -I file - read command input from file (echo mode)\n" " -l file - log all console input/output to file\n" " -o file - log console input to file\n" " -plain - run in plain mode (no cursor positioning, " "colors, etc.)\n" " -r file - restore saved state from file\n" " -R dir - set directory for external resources\n" " -s# - set I/O safety level (# in range 0 to 4 - 0 " "is the least\n" " restrictive, 4 allows no file I/O at all)\n" "\n" "If provided, the optional extra arguments are passed " "to the program's\n" "main entrypoint.\n", T3VM_BANNER_STRING, executable_name, load_from_exe ? "[- " : "<image-file-name> ["); /* display the message */ clientifc->display_error(0, buf, FALSE); } /* return failure */ return OSEXFAIL; } /* * if we're in test mode, replace the first argument to the program * with its root name, so that we don't include any path information * in the argument list */ if (test_mode && curarg <= argc && argv[curarg] != 0) argv[curarg] = os_get_root_name(argv[curarg]); /* run the program */ stat = vm_run_image(clientifc, image_file_name, hostifc, argv + curarg, argc - curarg, script_file, script_quiet, log_file, cmd_log_file, load_from_exe, show_banner, charset, log_charset, saved_state, res_dir); /* return the status code */ return stat; }