/* * Execute an image file. If an exception occurs, we'll display a * message on the console, and we'll return the error code; we'll return * zero on success. If an error occurs, we'll fill in 'errbuf' with a * message describing the problem. */ int vm_run_image(CVmMainClientIfc *clientifc, const char *image_file_name, class CVmHostIfc *hostifc, const char *const *prog_argv, int prog_argc, const char *script_file, int script_quiet, const char *log_file, const char *cmd_log_file, int load_from_exe, int show_banner, const char *charset, const char *log_charset, const char *saved_state, const char *res_dir) { CVmFile *fp = 0; CVmImageLoader *volatile loader = 0; CVmImageFile *volatile imagefp = 0; unsigned long image_file_base = 0; int retval; vm_globals *vmg__; /* presume we will return success */ retval = 0; /* create the file object */ fp = new CVmFile(); /* initialize the VM */ vm_init_options opts(hostifc, clientifc, charset, log_charset); vm_initialize(&vmg__, &opts); /* tell the client system to initialize */ clientifc->client_init(VMGLOB_ADDR, script_file, script_quiet, log_file, cmd_log_file, show_banner ? T3VM_BANNER_STRING : 0); /* catch any errors that occur during loading and running */ err_try { /* remember the name of the byte-code file */ strncpy(G_os_gamename, image_file_name, sizeof(G_os_gamename)); G_os_gamename[sizeof(G_os_gamename) - 1] = '\0'; if (load_from_exe) { osfildef *exe_fp; /* find the image within the executable */ exe_fp = os_exeseek(image_file_name, "TGAM"); if (exe_fp == 0) err_throw(VMERR_NO_IMAGE_IN_EXE); /* * set up to read from the executable at the location of the * embedded image file that we just found */ image_file_base = osfpos(exe_fp); fp->set_file(exe_fp, image_file_base); } else { /* reading from a normal file - open the file */ fp->open_read(image_file_name, OSFTT3IMG); } /* create the loader */ imagefp = new CVmImageFileExt(fp); loader = new CVmImageLoader(imagefp, image_file_name, image_file_base); /* load the image */ loader->load(vmg0_); /* if we have a resource root path, tell the host interface */ if (res_dir != 0) hostifc->set_res_dir(res_dir); /* let the client prepare for execution */ clientifc->pre_exec(VMGLOB_ADDR); /* run the program from the main entrypoint */ loader->run(vmg_ prog_argv, prog_argc, 0, saved_state); /* tell the client we're done with execution */ clientifc->post_exec(VMGLOB_ADDR); } err_catch(exc) { char errbuf[512]; /* tell the client execution failed due to an error */ clientifc->post_exec_err(VMGLOB_ADDR); /* note the error code for returning to the caller */ retval = exc->get_error_code(); /* get the message for the error */ CVmRun::get_exc_message(vmg_ exc, errbuf, sizeof(errbuf), TRUE); /* display the message */ clientifc->display_error(VMGLOB_ADDR, errbuf, FALSE); } err_end; /* unload the image */ if (loader != 0) loader->unload(vmg0_); /* delete the loader and the image file object */ if (loader != 0) delete loader; if (imagefp != 0) delete imagefp; /* notify the client */ clientifc->client_terminate(VMGLOB_ADDR); /* terminate the VM */ vm_terminate(vmg__, clientifc); /* delete the file */ if (fp != 0) delete fp; /* return the status code */ return retval; }
/* * Run pre-initialization */ void vm_run_preinit(CVmFile *origfp, const char *image_fname, CVmFile *newfp, class CVmHostIfc *hostifc, class CVmMainClientIfc *clientifc, const char *const *argv, int argc, class CVmRuntimeSymbols *runtime_symtab, class CVmRuntimeSymbols *runtime_macros) { vm_globals *vmg__; CVmImageLoader *volatile loader = 0; CVmImageFile *volatile imagefp = 0; /* initialize the VM */ vm_init_options opts(hostifc, clientifc); vm_initialize(&vmg__, &opts); /* * turn off "more" on the console - when running preinitialization, * any output is purely diagnostic information for the programmer * and thus should be formatted as simple stdio-style console output */ G_console->set_more_state(FALSE); err_try { /* note where the image file starts */ long start_pos = origfp->get_pos(); /* create the loader */ imagefp = new CVmImageFileExt(origfp); loader = new CVmImageLoader(imagefp, image_fname, 0); /* load the image */ loader->load(vmg0_); /* set pre-init mode */ G_preinit_mode = TRUE; /* run it, using the runtime symbols the caller sent us */ loader->run(vmg_ argv, argc, runtime_symtab, runtime_macros, 0); /* * seek back to the start of the image file, since we need to * copy parts of the original file to the new file */ origfp->set_pos(start_pos); /* save the new image file */ vm_rewrite_image(vmg_ origfp, newfp, loader->get_static_cs_ofs()); } err_finally { /* detach the pools from the image file */ if (loader != 0) loader->unload(vmg0_); /* delete the loader and the image file object */ if (loader != 0) delete loader; if (imagefp != 0) delete imagefp; /* terminate the VM */ vm_terminate(vmg__, clientifc); } err_end; }
int main(int argc, char **argv) { CImageFile *imagefp; vm_val_t val; vm_val_t *stkval; vm_globals *vmg__; CVmHostIfc *hostifc; CVmMainClientConsole clientifc; /* initialize for testing */ test_init(); /* initialize the VM */ hostifc = new CVmHostIfcStdio(argv[0]); vm_initialize(&vmg__, &vm_init_options(hostifc, &clientifc, "us-ascii", "us_ascii")); /* create a fake host file object */ imagefp = new CImageFile(); /* create the constant pool */ G_const_pool->attach_backing_store(imagefp); /* create a couple of objects and push them on the stack */ val.set_obj(CVmObjTads::create(vmg_ FALSE, 0, 4)); G_stk->push(&val); val.set_obj(CVmObjTads::create(vmg_ FALSE, 0, 4)); G_stk->push(&val); /* * create another object, and store it in a property of the first * object */ val.set_obj(CVmObjTads::create(vmg_ FALSE, 0, 4)); stkval = G_stk->get(1); vm_objp(vmg_ stkval->val.obj)-> set_prop(vmg_ G_undo, stkval->val.obj, PROP_A, &val); /* collect garbage - nothing should be deleted at this point */ G_obj_table->gc_full(vmg0_); /* * forget about the second object by popping it off the stack, then * collect garbage again -- the second object should be deleted at * this point, because it's no longer reachable */ G_stk->discard(); G_obj_table->gc_full(vmg0_); /* * Force the first object's property table to expand by filling up * its initial table */ stkval = G_stk->get(0); val.set_nil(); vm_objp(vmg_ stkval->val.obj)-> set_prop(vmg_ G_undo, stkval->val.obj, PROP_A, &val); vm_objp(vmg_ stkval->val.obj)-> set_prop(vmg_ G_undo, stkval->val.obj, PROP_B, &val); vm_objp(vmg_ stkval->val.obj)-> set_prop(vmg_ G_undo, stkval->val.obj, PROP_C, &val); vm_objp(vmg_ stkval->val.obj)-> set_prop(vmg_ G_undo, stkval->val.obj, PROP_D, &val); vm_objp(vmg_ stkval->val.obj)-> set_prop(vmg_ G_undo, stkval->val.obj, PROP_E, &val); /* set an existing property */ vm_objp(vmg_ stkval->val.obj)-> set_prop(vmg_ G_undo, stkval->val.obj, PROP_B, &val); /* we're done, so delete all of our managers */ G_const_pool->detach_backing_store(); delete imagefp; /* shut down the VM */ vm_terminate(vmg__, &clientifc); /* delete the host interface */ delete hostifc; /* terminate */ return 0; }