| | 1 | #ifdef RCSID |
| | 2 | static char RCSid[] = |
| | 3 | "$Header: d:/cvsroot/tads/tads3/VMINIT.CPP,v 1.3 1999/07/11 00:46:58 MJRoberts Exp $"; |
| | 4 | #endif |
| | 5 | |
| | 6 | /* |
| | 7 | * Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved. |
| | 8 | * |
| | 9 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 10 | * on using and copying this software. |
| | 11 | */ |
| | 12 | /* |
| | 13 | Name |
| | 14 | vminit.cpp - initialize and terminate VM processing |
| | 15 | Function |
| | 16 | Provides functions to create and destroy global objects for a VM |
| | 17 | session. |
| | 18 | Notes |
| | 19 | |
| | 20 | Modified |
| | 21 | 04/06/99 MJRoberts - Creation |
| | 22 | */ |
| | 23 | |
| | 24 | #include <string.h> |
| | 25 | |
| | 26 | #include "t3std.h" |
| | 27 | #include "charmap.h" |
| | 28 | #include "vminit.h" |
| | 29 | #include "vmerr.h" |
| | 30 | #include "vmfile.h" |
| | 31 | #include "vmimage.h" |
| | 32 | #include "vmpool.h" |
| | 33 | #include "vmobj.h" |
| | 34 | #include "vmstack.h" |
| | 35 | #include "vmundo.h" |
| | 36 | #include "vmmeta.h" |
| | 37 | #include "vmbif.h" |
| | 38 | #include "vmrun.h" |
| | 39 | #include "vmpredef.h" |
| | 40 | #include "vmmcreg.h" |
| | 41 | #include "vmbiftad.h" |
| | 42 | #include "resload.h" |
| | 43 | #include "vmhost.h" |
| | 44 | #include "vmconsol.h" |
| | 45 | #include "vmbignum.h" |
| | 46 | #include "vmsrcf.h" |
| | 47 | #include "vmparam.h" |
| | 48 | #include "vmmain.h" |
| | 49 | #include "vmtobj.h" |
| | 50 | |
| | 51 | |
| | 52 | /* ------------------------------------------------------------------------ */ |
| | 53 | /* |
| | 54 | * Perform base initialization. This is an internal routine called only |
| | 55 | * by higher-level initialization routines; we perform all of the |
| | 56 | * generic, configuration-independent initialization. |
| | 57 | */ |
| | 58 | void vm_init_base(vm_globals **vmg, const vm_init_options *opts) |
| | 59 | { |
| | 60 | vm_globals *vmg__; |
| | 61 | char disp_mapname[32]; |
| | 62 | char filename_mapname[32]; |
| | 63 | char filecont_mapname[32]; |
| | 64 | CResLoader *map_loader; |
| | 65 | int disp_map_err; |
| | 66 | const char *charset = opts->charset; |
| | 67 | |
| | 68 | /* |
| | 69 | * Allocate globals according to build-time configuration, then |
| | 70 | * assign the global pointer to a local named vmg__. This will |
| | 71 | * ensure that the globals are accessible for all of the different |
| | 72 | * build-time configurations. |
| | 73 | */ |
| | 74 | vmg__ = *vmg = vmglob_alloc(); |
| | 75 | |
| | 76 | /* initialize the error stack */ |
| | 77 | err_init(VM_ERR_STACK_BYTES); |
| | 78 | |
| | 79 | /* get the character map loader from the host interface */ |
| | 80 | map_loader = opts->hostifc->get_cmap_res_loader(); |
| | 81 | |
| | 82 | /* if an external message set hasn't been loaded, try loading one */ |
| | 83 | if (!err_is_message_file_loaded() && map_loader != 0) |
| | 84 | { |
| | 85 | osfildef *fp; |
| | 86 | |
| | 87 | /* try finding a message file */ |
| | 88 | fp = map_loader->open_res_file(VM_ERR_MSG_FNAME, 0, |
| | 89 | VM_ERR_MSG_RESTYPE); |
| | 90 | if (fp != 0) |
| | 91 | { |
| | 92 | /* |
| | 93 | * try loading it - if that fails, we'll just be left with |
| | 94 | * the built-in messages, so we won't have lost anything for |
| | 95 | * trying |
| | 96 | */ |
| | 97 | err_load_vm_message_file(fp); |
| | 98 | |
| | 99 | /* we're done with the file */ |
| | 100 | osfcls(fp); |
| | 101 | } |
| | 102 | } |
| | 103 | |
| | 104 | /* remember the host interface */ |
| | 105 | G_host_ifc = opts->hostifc; |
| | 106 | |
| | 107 | /* we don't have a resource loader for program resources yet */ |
| | 108 | G_res_loader = 0; |
| | 109 | |
| | 110 | /* create the object table */ |
| | 111 | VM_IFELSE_ALLOC_PRE_GLOBAL(G_obj_table = new CVmObjTable(), |
| | 112 | G_obj_table->init()); |
| | 113 | |
| | 114 | /* |
| | 115 | * Create the memory manager. Empirically, our hybrid heap allocator |
| | 116 | * is faster than the standard C++ run-time library's allocator on many |
| | 117 | * platforms, so use it instead of hte basic 'malloc' allocator. |
| | 118 | */ |
| | 119 | G_varheap = new CVmVarHeapHybrid(); |
| | 120 | // G_varheap = new CVmVarHeapMalloc(); to use the system 'malloc' instead |
| | 121 | G_mem = new CVmMemory(vmg_ G_varheap); |
| | 122 | |
| | 123 | /* create a stack */ |
| | 124 | VM_IFELSE_ALLOC_PRE_GLOBAL( |
| | 125 | G_stk = new CVmStack(VM_STACK_SIZE, vm_init_stack_reserve()), |
| | 126 | G_stk->init()); |
| | 127 | |
| | 128 | /* create the undo manager */ |
| | 129 | G_undo = new CVmUndo(VM_UNDO_MAX_RECORDS, VM_UNDO_MAX_SAVEPTS); |
| | 130 | |
| | 131 | /* create the metafile and function set tables */ |
| | 132 | G_meta_table = new CVmMetaTable(5); |
| | 133 | G_bif_table = new CVmBifTable(5); |
| | 134 | |
| | 135 | /* initialize the metaclass registration tables */ |
| | 136 | vm_register_metaclasses(); |
| | 137 | |
| | 138 | /* initialize the TadsObject class */ |
| | 139 | CVmObjTads::class_init(vmg0_); |
| | 140 | |
| | 141 | /* create the byte-code interpreter */ |
| | 142 | VM_IFELSE_ALLOC_PRE_GLOBAL(G_interpreter = new CVmRun(), |
| | 143 | G_interpreter->init()); |
| | 144 | |
| | 145 | /* presume we won't create debugger information */ |
| | 146 | G_debugger = 0; |
| | 147 | G_srcf_table = 0; |
| | 148 | |
| | 149 | /* initialize the debugger if present */ |
| | 150 | vm_init_debugger(vmg0_); |
| | 151 | |
| | 152 | /* create the source file table */ |
| | 153 | G_srcf_table = new CVmSrcfTable(); |
| | 154 | |
| | 155 | /* create the pre-defined object mapper */ |
| | 156 | VM_IFELSE_ALLOC_PRE_GLOBAL(G_predef = new CVmPredef, G_predef->reset()); |
| | 157 | |
| | 158 | /* presume we're in normal execution mode (not preinit) */ |
| | 159 | G_preinit_mode = FALSE; |
| | 160 | |
| | 161 | /* allocate the TADS intrinsic function set's globals */ |
| | 162 | G_bif_tads_globals = new CVmBifTADSGlobals(vmg0_); |
| | 163 | |
| | 164 | /* allocate the BigNumber register cache */ |
| | 165 | G_bignum_cache = new CVmBigNumCache(32); |
| | 166 | |
| | 167 | /* no image loader yet */ |
| | 168 | G_image_loader = 0; |
| | 169 | |
| | 170 | /* |
| | 171 | * If the caller explicitly specified a character set, use it. |
| | 172 | * Otherwise, ask the OS layer for the default character set we |
| | 173 | * should use. |
| | 174 | */ |
| | 175 | if (charset == 0) |
| | 176 | { |
| | 177 | /* the user did not specify a mapping - ask the OS for the default */ |
| | 178 | os_get_charmap(disp_mapname, OS_CHARMAP_DISPLAY); |
| | 179 | |
| | 180 | /* use the name we got from the OS */ |
| | 181 | charset = disp_mapname; |
| | 182 | |
| | 183 | /* there's no explicit global character set name setting to store */ |
| | 184 | G_disp_cset_name = 0; |
| | 185 | } |
| | 186 | else |
| | 187 | { |
| | 188 | /* save the global character set name */ |
| | 189 | G_disp_cset_name = lib_copy_str(charset); |
| | 190 | } |
| | 191 | |
| | 192 | /* create the display character maps */ |
| | 193 | G_cmap_from_ui = CCharmapToUni::load(map_loader, charset); |
| | 194 | G_cmap_to_ui = CCharmapToLocal::load(map_loader, charset); |
| | 195 | |
| | 196 | /* create the filename character maps */ |
| | 197 | os_get_charmap(filename_mapname, OS_CHARMAP_FILENAME); |
| | 198 | G_cmap_from_fname = CCharmapToUni::load(map_loader, filename_mapname); |
| | 199 | G_cmap_to_fname = CCharmapToLocal::load(map_loader, filename_mapname); |
| | 200 | |
| | 201 | /* create the file-contents character maps */ |
| | 202 | os_get_charmap(filecont_mapname, OS_CHARMAP_FILECONTENTS); |
| | 203 | G_cmap_from_file = CCharmapToUni::load(map_loader, filecont_mapname); |
| | 204 | G_cmap_to_file = CCharmapToLocal::load(map_loader, filecont_mapname); |
| | 205 | |
| | 206 | /* |
| | 207 | * If the caller specified a separate log-file character set, create |
| | 208 | * the mapping. Otherwise, just use the to-file mapper for log files. |
| | 209 | */ |
| | 210 | if (opts->log_charset != 0) |
| | 211 | { |
| | 212 | /* load the specified log file output mapping */ |
| | 213 | G_cmap_to_log = CCharmapToLocal::load(map_loader, opts->log_charset); |
| | 214 | } |
| | 215 | else |
| | 216 | { |
| | 217 | /* no log file mapping is specified, so use the generic file map */ |
| | 218 | if ((G_cmap_to_log = G_cmap_to_file) != 0) |
| | 219 | G_cmap_to_log->add_ref(); |
| | 220 | } |
| | 221 | |
| | 222 | /* make a note of whether we had any problems loading the maps */ |
| | 223 | disp_map_err = (G_cmap_from_ui == 0 || G_cmap_to_ui == 0); |
| | 224 | |
| | 225 | /* if we failed to create any of the maps, load defaults */ |
| | 226 | if (G_cmap_from_ui == 0) |
| | 227 | G_cmap_from_ui = CCharmapToUni::load(map_loader, "us-ascii"); |
| | 228 | if (G_cmap_to_ui == 0) |
| | 229 | G_cmap_to_ui = CCharmapToLocal::load(map_loader, "us-ascii"); |
| | 230 | if (G_cmap_from_fname == 0) |
| | 231 | G_cmap_from_fname = CCharmapToUni::load(map_loader, "us-ascii"); |
| | 232 | if (G_cmap_to_fname == 0) |
| | 233 | G_cmap_to_fname = CCharmapToLocal::load(map_loader, "us-ascii"); |
| | 234 | if (G_cmap_from_file == 0) |
| | 235 | G_cmap_from_file = CCharmapToUni::load(map_loader, "us-ascii"); |
| | 236 | if (G_cmap_to_file == 0) |
| | 237 | G_cmap_to_file = CCharmapToLocal::load(map_loader, "us-ascii"); |
| | 238 | if (G_cmap_to_log == 0) |
| | 239 | G_cmap_to_log = CCharmapToLocal::load(map_loader, "us-ascii"); |
| | 240 | |
| | 241 | /* create the primary console */ |
| | 242 | G_console = opts->clientifc->create_console(VMGLOB_ADDR); |
| | 243 | |
| | 244 | /* |
| | 245 | * if we had any trouble opening the display character mapping file, |
| | 246 | * make a note that we are using a default mapping |
| | 247 | */ |
| | 248 | if (disp_map_err) |
| | 249 | { |
| | 250 | const char *msg; |
| | 251 | char buf[256]; |
| | 252 | |
| | 253 | /* get the message */ |
| | 254 | msg = err_get_msg(vm_messages, vm_message_count, |
| | 255 | VMERR_NO_CHARMAP_FILE, TRUE); |
| | 256 | |
| | 257 | /* format it */ |
| | 258 | sprintf(buf, msg, charset); |
| | 259 | |
| | 260 | /* display it */ |
| | 261 | opts->clientifc->display_error(VMGLOB_ADDR, buf, TRUE); |
| | 262 | } |
| | 263 | } |
| | 264 | |
| | 265 | /* ------------------------------------------------------------------------ */ |
| | 266 | /* |
| | 267 | * Terminate the VM |
| | 268 | */ |
| | 269 | void vm_terminate(vm_globals *vmg__, CVmMainClientIfc *clientifc) |
| | 270 | { |
| | 271 | /* tell the debugger to shut down, if necessary */ |
| | 272 | vm_terminate_debug_shutdown(vmg0_); |
| | 273 | |
| | 274 | /* drop all undo information */ |
| | 275 | G_undo->drop_undo(vmg0_); |
| | 276 | |
| | 277 | /* delete the main console */ |
| | 278 | clientifc->delete_console(VMGLOB_ADDR, G_console); |
| | 279 | |
| | 280 | /* release references on the character mappers */ |
| | 281 | G_cmap_from_fname->release_ref(); |
| | 282 | G_cmap_to_fname->release_ref(); |
| | 283 | G_cmap_from_ui->release_ref(); |
| | 284 | G_cmap_to_ui->release_ref(); |
| | 285 | G_cmap_from_file->release_ref(); |
| | 286 | G_cmap_to_file->release_ref(); |
| | 287 | G_cmap_to_log->release_ref(); |
| | 288 | |
| | 289 | /* delete the saved UI character set name, if any */ |
| | 290 | lib_free_str(G_disp_cset_name); |
| | 291 | |
| | 292 | /* delete the BigNumber register cache */ |
| | 293 | delete G_bignum_cache; |
| | 294 | |
| | 295 | /* delete the TADS intrinsic function set's globals */ |
| | 296 | delete G_bif_tads_globals; |
| | 297 | |
| | 298 | /* delete the predefined object table */ |
| | 299 | VM_IF_ALLOC_PRE_GLOBAL(delete G_predef); |
| | 300 | |
| | 301 | /* delete the interpreter */ |
| | 302 | VM_IFELSE_ALLOC_PRE_GLOBAL(delete G_interpreter, |
| | 303 | G_interpreter->terminate()); |
| | 304 | |
| | 305 | /* terminate the TadsObject class */ |
| | 306 | CVmObjTads::class_term(vmg0_); |
| | 307 | |
| | 308 | /* delete the source file table */ |
| | 309 | delete G_srcf_table; |
| | 310 | |
| | 311 | /* delete debugger objects */ |
| | 312 | vm_terminate_debug_delete(vmg0_); |
| | 313 | |
| | 314 | /* delete the constant pools */ |
| | 315 | VM_IFELSE_ALLOC_PRE_GLOBAL(delete G_code_pool, |
| | 316 | G_code_pool->terminate()); |
| | 317 | VM_IFELSE_ALLOC_PRE_GLOBAL(delete G_const_pool, |
| | 318 | G_const_pool->terminate()); |
| | 319 | |
| | 320 | /* delete the dependency tables */ |
| | 321 | delete G_meta_table; |
| | 322 | delete G_bif_table; |
| | 323 | |
| | 324 | /* delete the undo manager */ |
| | 325 | delete G_undo; |
| | 326 | |
| | 327 | /* delete the stack */ |
| | 328 | VM_IF_ALLOC_PRE_GLOBAL(delete G_stk); |
| | 329 | |
| | 330 | /* delete the object table */ |
| | 331 | G_obj_table->delete_obj_table(vmg0_); |
| | 332 | VM_IF_ALLOC_PRE_GLOBAL(delete G_obj_table); |
| | 333 | |
| | 334 | /* delete the memory manager and heap manager */ |
| | 335 | delete G_mem; |
| | 336 | delete G_varheap; |
| | 337 | |
| | 338 | /* delete the error context */ |
| | 339 | err_terminate(); |
| | 340 | |
| | 341 | /* delete the globals */ |
| | 342 | vmglob_delete(vmg__); |
| | 343 | } |
| | 344 | |