| | 1 | #ifdef RCSID |
| | 2 | static char RCSid[] = |
| | 3 | "$Header$"; |
| | 4 | #endif |
| | 5 | |
| | 6 | /* |
| | 7 | * Copyright (c) 2000, 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 | vmbiftio.cpp - TADS Input/Output functions |
| | 15 | Function |
| | 16 | |
| | 17 | Notes |
| | 18 | |
| | 19 | Modified |
| | 20 | 02/08/00 MJRoberts - Creation |
| | 21 | */ |
| | 22 | |
| | 23 | #include <stdio.h> |
| | 24 | #include <string.h> |
| | 25 | #include <time.h> |
| | 26 | |
| | 27 | #include "t3std.h" |
| | 28 | #include "os.h" |
| | 29 | #include "utf8.h" |
| | 30 | #include "charmap.h" |
| | 31 | #include "vmbiftio.h" |
| | 32 | #include "vmstack.h" |
| | 33 | #include "vmerr.h" |
| | 34 | #include "vmerrnum.h" |
| | 35 | #include "vmglob.h" |
| | 36 | #include "vmpool.h" |
| | 37 | #include "vmobj.h" |
| | 38 | #include "vmstr.h" |
| | 39 | #include "vmlst.h" |
| | 40 | #include "vmrun.h" |
| | 41 | #include "vmfile.h" |
| | 42 | #include "vmconsol.h" |
| | 43 | #include "vmstrres.h" |
| | 44 | #include "vmvsn.h" |
| | 45 | #include "vmhost.h" |
| | 46 | #include "vmpredef.h" |
| | 47 | #include "vmcset.h" |
| | 48 | #include "vmfilobj.h" |
| | 49 | |
| | 50 | |
| | 51 | /* ------------------------------------------------------------------------ */ |
| | 52 | /* |
| | 53 | * Display a value |
| | 54 | */ |
| | 55 | void CVmBifTIO::say(VMG_ uint argc) |
| | 56 | { |
| | 57 | /* write the value to the main console */ |
| | 58 | say_to_console(vmg_ G_console, argc); |
| | 59 | } |
| | 60 | |
| | 61 | /* |
| | 62 | * Display the value or values at top of stack to the given console |
| | 63 | */ |
| | 64 | void CVmBifTIO::say_to_console(VMG_ CVmConsole *console, uint argc) |
| | 65 | { |
| | 66 | vm_val_t val; |
| | 67 | const char *str; |
| | 68 | char buf[30]; |
| | 69 | size_t len; |
| | 70 | vm_val_t new_str; |
| | 71 | |
| | 72 | /* presume we won't need to create a new string value */ |
| | 73 | new_str.set_nil(); |
| | 74 | |
| | 75 | /* display each argument */ |
| | 76 | for ( ; argc != 0 ; --argc) |
| | 77 | { |
| | 78 | /* get our argument */ |
| | 79 | G_stk->pop(&val); |
| | 80 | |
| | 81 | /* see what we have */ |
| | 82 | switch(val.typ) |
| | 83 | { |
| | 84 | case VM_SSTRING: |
| | 85 | /* get the string */ |
| | 86 | str = G_const_pool->get_ptr(val.val.ofs); |
| | 87 | |
| | 88 | /* the original value is our string */ |
| | 89 | new_str = val; |
| | 90 | |
| | 91 | disp_str: |
| | 92 | /* push the string to protect from garbage collection */ |
| | 93 | G_stk->push(&new_str); |
| | 94 | |
| | 95 | /* display the string through the output formatter */ |
| | 96 | console->format_text(vmg_ str + 2, osrp2(str)); |
| | 97 | |
| | 98 | /* discard the saved string now that we no longer need it */ |
| | 99 | G_stk->discard(); |
| | 100 | |
| | 101 | /* done */ |
| | 102 | break; |
| | 103 | |
| | 104 | case VM_OBJ: |
| | 105 | /* convert it to a string */ |
| | 106 | str = vm_objp(vmg_ val.val.obj) |
| | 107 | ->cast_to_string(vmg_ val.val.obj, &new_str); |
| | 108 | |
| | 109 | /* go display it */ |
| | 110 | goto disp_str; |
| | 111 | |
| | 112 | case VM_INT: |
| | 113 | /* convert it to a string */ |
| | 114 | sprintf(buf + 2, "%ld", val.val.intval); |
| | 115 | |
| | 116 | /* set its length */ |
| | 117 | len = strlen(buf + 2); |
| | 118 | oswp2(buf, len); |
| | 119 | |
| | 120 | /* display it */ |
| | 121 | str = buf; |
| | 122 | goto disp_str; |
| | 123 | |
| | 124 | case VM_NIL: |
| | 125 | /* display nothing */ |
| | 126 | break; |
| | 127 | |
| | 128 | default: |
| | 129 | /* other types are invalid */ |
| | 130 | err_throw(VMERR_BAD_TYPE_BIF); |
| | 131 | } |
| | 132 | } |
| | 133 | } |
| | 134 | |
| | 135 | /* ------------------------------------------------------------------------ */ |
| | 136 | /* |
| | 137 | * Logging - turn on or off output text capture |
| | 138 | */ |
| | 139 | |
| | 140 | #define LOG_SCRIPT 1 |
| | 141 | #define LOG_CMD 2 |
| | 142 | #define LOG_EVENT 3 |
| | 143 | |
| | 144 | void CVmBifTIO::logging(VMG_ uint argc) |
| | 145 | { |
| | 146 | vm_val_t fname_val; |
| | 147 | int log_type; |
| | 148 | |
| | 149 | /* check arguments */ |
| | 150 | check_argc_range(vmg_ argc, 1, 2); |
| | 151 | |
| | 152 | /* retrieve the filename argument */ |
| | 153 | G_stk->pop(&fname_val); |
| | 154 | |
| | 155 | /* get the log type argument, if present */ |
| | 156 | log_type = (argc >= 2 ? pop_int_val(vmg0_) : LOG_SCRIPT); |
| | 157 | |
| | 158 | /* |
| | 159 | * if they passed us nil, turn off logging; otherwise, start logging |
| | 160 | * to the filename given by the string |
| | 161 | */ |
| | 162 | if (fname_val.typ == VM_NIL) |
| | 163 | { |
| | 164 | /* turn off the appropriate type of logging */ |
| | 165 | switch(log_type) |
| | 166 | { |
| | 167 | case LOG_SCRIPT: |
| | 168 | G_console->close_log_file(); |
| | 169 | break; |
| | 170 | |
| | 171 | case LOG_CMD: |
| | 172 | case LOG_EVENT: |
| | 173 | G_console->close_command_log(); |
| | 174 | break; |
| | 175 | |
| | 176 | default: |
| | 177 | err_throw(VMERR_BAD_VAL_BIF); |
| | 178 | } |
| | 179 | } |
| | 180 | else |
| | 181 | { |
| | 182 | char fname[OSFNMAX]; |
| | 183 | |
| | 184 | /* |
| | 185 | * get the filename string (converted to the file system |
| | 186 | * character set) |
| | 187 | */ |
| | 188 | G_stk->push(&fname_val); |
| | 189 | pop_str_val_fname(vmg_ fname, sizeof(fname)); |
| | 190 | |
| | 191 | /* open the appropriate log file */ |
| | 192 | switch(log_type) |
| | 193 | { |
| | 194 | case LOG_SCRIPT: |
| | 195 | G_console->open_log_file(fname); |
| | 196 | break; |
| | 197 | |
| | 198 | case LOG_CMD: |
| | 199 | case LOG_EVENT: |
| | 200 | G_console->open_command_log(fname, log_type == LOG_EVENT); |
| | 201 | break; |
| | 202 | |
| | 203 | default: |
| | 204 | err_throw(VMERR_BAD_VAL_BIF); |
| | 205 | } |
| | 206 | } |
| | 207 | } |
| | 208 | |
| | 209 | /* ------------------------------------------------------------------------ */ |
| | 210 | /* |
| | 211 | * clearscreen - clear the main display screen |
| | 212 | */ |
| | 213 | void CVmBifTIO::clearscreen(VMG_ uint argc) |
| | 214 | { |
| | 215 | /* check arguments */ |
| | 216 | check_argc(vmg_ argc, 0); |
| | 217 | |
| | 218 | /* ask the console to clear the screen */ |
| | 219 | G_console->clear_window(vmg0_); |
| | 220 | } |
| | 221 | |
| | 222 | /* ------------------------------------------------------------------------ */ |
| | 223 | /* |
| | 224 | * more - show MORE prompt |
| | 225 | */ |
| | 226 | void CVmBifTIO::more(VMG_ uint argc) |
| | 227 | { |
| | 228 | /* check arguments */ |
| | 229 | check_argc(vmg_ argc, 0); |
| | 230 | |
| | 231 | /* |
| | 232 | * if we're reading from a script, ignore this request - these types of |
| | 233 | * interactive pauses are irrelevant when reading a script, since we're |
| | 234 | * getting our input non-interactively |
| | 235 | */ |
| | 236 | if (G_console->is_reading_script()) |
| | 237 | return; |
| | 238 | |
| | 239 | /* flush the display output */ |
| | 240 | G_console->flush_all(vmg_ VM_NL_NONE); |
| | 241 | |
| | 242 | /* show the MORE prompt */ |
| | 243 | G_console->show_more_prompt(vmg0_); |
| | 244 | } |
| | 245 | |
| | 246 | /* ------------------------------------------------------------------------ */ |
| | 247 | /* |
| | 248 | * input - get a line of input from the keyboard |
| | 249 | */ |
| | 250 | void CVmBifTIO::input(VMG_ uint argc) |
| | 251 | { |
| | 252 | char buf[256]; |
| | 253 | |
| | 254 | /* check arguments */ |
| | 255 | check_argc(vmg_ argc, 0); |
| | 256 | |
| | 257 | /* read a line of text from the keyboard */ |
| | 258 | if (G_console->read_line(vmg_ buf, sizeof(buf))) |
| | 259 | { |
| | 260 | /* end of file - return nil */ |
| | 261 | retval_nil(vmg0_); |
| | 262 | } |
| | 263 | else |
| | 264 | { |
| | 265 | /* return the string */ |
| | 266 | retval_str(vmg_ buf); |
| | 267 | } |
| | 268 | } |
| | 269 | |
| | 270 | /* ------------------------------------------------------------------------ */ |
| | 271 | /* |
| | 272 | * inputkey - read a keystroke |
| | 273 | */ |
| | 274 | void CVmBifTIO::inputkey(VMG_ uint argc) |
| | 275 | { |
| | 276 | char buf[32]; |
| | 277 | char c[10]; |
| | 278 | size_t len; |
| | 279 | int evt; |
| | 280 | static const int filter[] = { OS_EVT_KEY }; |
| | 281 | |
| | 282 | /* check arguments */ |
| | 283 | check_argc(vmg_ argc, 0); |
| | 284 | |
| | 285 | /* check for script input */ |
| | 286 | if (G_console->read_event_script( |
| | 287 | vmg_ &evt, buf, sizeof(buf), |
| | 288 | filter, sizeof(filter)/sizeof(filter[0]), 0)) |
| | 289 | { |
| | 290 | /* we got a key from the script */ |
| | 291 | retval_ui_str(vmg_ buf); |
| | 292 | |
| | 293 | /* log the event */ |
| | 294 | G_console->log_event(vmg_ OS_EVT_KEY, buf, strlen(buf), FALSE); |
| | 295 | |
| | 296 | /* done */ |
| | 297 | return; |
| | 298 | } |
| | 299 | |
| | 300 | /* flush any output */ |
| | 301 | G_console->flush_all(vmg_ VM_NL_INPUT); |
| | 302 | |
| | 303 | /* get a keystroke */ |
| | 304 | c[0] = (char)os_getc_raw(); |
| | 305 | len = 1; |
| | 306 | |
| | 307 | /* if it's an extended key, map it specially */ |
| | 308 | if (c[0] == 0) |
| | 309 | { |
| | 310 | char extc; |
| | 311 | |
| | 312 | /* get the second part of the sequence */ |
| | 313 | extc = (char)os_getc_raw(); |
| | 314 | |
| | 315 | /* map the extended key */ |
| | 316 | map_ext_key(vmg_ buf, (unsigned char)extc); |
| | 317 | } |
| | 318 | else |
| | 319 | { |
| | 320 | /* continue fetching bytes until we have a full character */ |
| | 321 | while (!raw_key_complete(vmg_ c, len) && len + 1 < sizeof(c)) |
| | 322 | { |
| | 323 | /* |
| | 324 | * We don't yet have enough bytes for a complete character, so |
| | 325 | * read another raw byte. The keyboard driver should already |
| | 326 | * have queued up all of the bytes we need to complete the |
| | 327 | * character sequence, so there should never be a delay from |
| | 328 | * os_getc_raw() here - it should simply return the next byte |
| | 329 | * of the sequence immediately. |
| | 330 | */ |
| | 331 | c[len++] = (char)os_getc_raw(); |
| | 332 | } |
| | 333 | c[len] = '\0'; |
| | 334 | |
| | 335 | /* |
| | 336 | * translate the key from the local character set to UTF-8, and map |
| | 337 | * the extended key code to the portable representation |
| | 338 | */ |
| | 339 | map_raw_key(vmg_ buf, c, len); |
| | 340 | } |
| | 341 | |
| | 342 | /* reset the [MORE] counter */ |
| | 343 | G_console->reset_line_count(FALSE); |
| | 344 | |
| | 345 | /* log the event */ |
| | 346 | G_console->log_event(vmg_ OS_EVT_KEY, buf, strlen(buf), TRUE); |
| | 347 | |
| | 348 | /* return the string */ |
| | 349 | retval_str(vmg_ buf); |
| | 350 | } |
| | 351 | |
| | 352 | /* ------------------------------------------------------------------------ */ |
| | 353 | /* |
| | 354 | * inputevent - read an event |
| | 355 | */ |
| | 356 | void CVmBifTIO::inputevent(VMG_ uint argc) |
| | 357 | { |
| | 358 | int use_timeout; |
| | 359 | unsigned long timeout; |
| | 360 | os_event_info_t info; |
| | 361 | int evt; |
| | 362 | int ele_count; |
| | 363 | vm_obj_id_t lst_obj; |
| | 364 | CVmObjList *lst; |
| | 365 | char keyname[32]; |
| | 366 | vm_val_t val; |
| | 367 | int from_script = FALSE; |
| | 368 | static const int filter[] = |
| | 369 | { |
| | 370 | OS_EVT_KEY, OS_EVT_TIMEOUT, OS_EVT_NOTIMEOUT, |
| | 371 | OS_EVT_HREF, OS_EVT_EOF, OS_EVT_COMMAND |
| | 372 | }; |
| | 373 | |
| | 374 | /* check arguments */ |
| | 375 | check_argc_range(vmg_ argc, 0, 1); |
| | 376 | |
| | 377 | /* if there's a timeout argument, get it */ |
| | 378 | if (argc == 0) |
| | 379 | { |
| | 380 | /* there's no timeout */ |
| | 381 | use_timeout = FALSE; |
| | 382 | timeout = 0; |
| | 383 | } |
| | 384 | else if (G_stk->get(0)->typ == VM_NIL) |
| | 385 | { |
| | 386 | /* the timeout is nil, which is the same as no timeout */ |
| | 387 | use_timeout = FALSE; |
| | 388 | timeout = 0; |
| | 389 | |
| | 390 | /* discard the nil timeout value */ |
| | 391 | G_stk->discard(); |
| | 392 | } |
| | 393 | else |
| | 394 | { |
| | 395 | /* pop the timeout value */ |
| | 396 | timeout = pop_long_val(vmg0_); |
| | 397 | |
| | 398 | /* note that we have a timeout to use */ |
| | 399 | use_timeout = TRUE; |
| | 400 | } |
| | 401 | |
| | 402 | /* check for script input */ |
| | 403 | if (G_console->read_event_script( |
| | 404 | vmg_ &evt, info.href, sizeof(info.href), |
| | 405 | filter, sizeof(filter)/sizeof(filter[0]), 0)) |
| | 406 | { |
| | 407 | /* we got a script event - note it */ |
| | 408 | from_script = TRUE; |
| | 409 | |
| | 410 | /* translate certain events */ |
| | 411 | switch (evt) |
| | 412 | { |
| | 413 | case OS_EVT_COMMAND: |
| | 414 | /* read the numeric parameter */ |
| | 415 | info.cmd_id = atoi(info.href); |
| | 416 | break; |
| | 417 | } |
| | 418 | } |
| | 419 | else |
| | 420 | { |
| | 421 | /* flush any buffered output */ |
| | 422 | G_console->flush_all(vmg_ VM_NL_INPUT); |
| | 423 | |
| | 424 | /* reset the [MORE] counter */ |
| | 425 | G_console->reset_line_count(FALSE); |
| | 426 | |
| | 427 | /* read an event from the OS layer */ |
| | 428 | evt = os_get_event(timeout, use_timeout, &info); |
| | 429 | } |
| | 430 | |
| | 431 | /* figure out how big a list we need to allocate */ |
| | 432 | switch(evt) |
| | 433 | { |
| | 434 | case OS_EVT_KEY: |
| | 435 | /* |
| | 436 | * we need two elements - one for the event type code, one for the |
| | 437 | * keystroke string |
| | 438 | */ |
| | 439 | ele_count = 2; |
| | 440 | break; |
| | 441 | |
| | 442 | case OS_EVT_COMMAND: |
| | 443 | /* we need a second element for the command ID */ |
| | 444 | ele_count = 2; |
| | 445 | break; |
| | 446 | |
| | 447 | case OS_EVT_HREF: |
| | 448 | /* |
| | 449 | * we need two elements - one for the event type code, one for the |
| | 450 | * HREF string |
| | 451 | */ |
| | 452 | ele_count = 2; |
| | 453 | break; |
| | 454 | |
| | 455 | default: |
| | 456 | /* for anything else, we need only the event type code element */ |
| | 457 | ele_count = 1; |
| | 458 | break; |
| | 459 | } |
| | 460 | |
| | 461 | /* create the return list */ |
| | 462 | lst_obj = CVmObjList::create(vmg_ FALSE, ele_count); |
| | 463 | lst = (CVmObjList *)vm_objp(vmg_ lst_obj); |
| | 464 | |
| | 465 | /* save the list on the stack to protect against garbage collection */ |
| | 466 | val.set_obj(lst_obj); |
| | 467 | G_stk->push(&val); |
| | 468 | |
| | 469 | /* fill in the first element with the event type code */ |
| | 470 | val.set_int(evt); |
| | 471 | lst->cons_set_element(0, &val); |
| | 472 | |
| | 473 | /* set additional elements, according to the event type */ |
| | 474 | switch(evt) |
| | 475 | { |
| | 476 | case OS_EVT_KEY: |
| | 477 | /* map the extended or ordinary key, as appropriate */ |
| | 478 | if (from_script) |
| | 479 | { |
| | 480 | /* we got a key from the script - it's in the 'href' field */ |
| | 481 | val.set_obj(str_from_ui_str(vmg_ info.href)); |
| | 482 | |
| | 483 | /* log the event */ |
| | 484 | G_console->log_event( |
| | 485 | vmg_ OS_EVT_KEY, info.href, strlen(info.href), FALSE); |
| | 486 | } |
| | 487 | else if (info.key[0] == 0) |
| | 488 | { |
| | 489 | /* it's an extended key */ |
| | 490 | map_ext_key(vmg_ keyname, info.key[1]); |
| | 491 | |
| | 492 | /* create a string for the key name */ |
| | 493 | val.set_obj(CVmObjString::create( |
| | 494 | vmg_ FALSE, keyname, strlen(keyname))); |
| | 495 | |
| | 496 | /* log the event */ |
| | 497 | G_console->log_event( |
| | 498 | vmg_ OS_EVT_KEY, keyname, strlen(keyname), TRUE); |
| | 499 | } |
| | 500 | else |
| | 501 | { |
| | 502 | char c[4]; |
| | 503 | size_t len; |
| | 504 | |
| | 505 | /* fetch more bytes until we have a complete character */ |
| | 506 | for (c[0] = (char)info.key[0], len = 1 ; |
| | 507 | !raw_key_complete(vmg_ c, len) && len < sizeof(c) ; ) |
| | 508 | { |
| | 509 | /* |
| | 510 | * Read another input event. The keyboard driver should |
| | 511 | * already have queued up all of the bytes needed to |
| | 512 | * complete this character sequence, so there should never |
| | 513 | * be a delay from os_get_event() here - it should simply |
| | 514 | * return immediately with another OS_EVT_KEY event with |
| | 515 | * the next byte of the sequence. |
| | 516 | */ |
| | 517 | evt = os_get_event(0, FALSE, &info); |
| | 518 | |
| | 519 | /* |
| | 520 | * if it's not a keystroke event, something's wrong - |
| | 521 | * ignore the event and stop trying to read the remaining |
| | 522 | * bytes of the character sequence |
| | 523 | */ |
| | 524 | if (evt != OS_EVT_KEY) |
| | 525 | break; |
| | 526 | |
| | 527 | /* store the next byte of the sequence */ |
| | 528 | c[len++] = (char)info.key[0]; |
| | 529 | } |
| | 530 | |
| | 531 | /* it's an ordinary key - map it */ |
| | 532 | map_raw_key(vmg_ keyname, c, len); |
| | 533 | |
| | 534 | /* create a string for the key name */ |
| | 535 | val.set_obj(CVmObjString::create( |
| | 536 | vmg_ FALSE, keyname, strlen(keyname))); |
| | 537 | |
| | 538 | /* log the event */ |
| | 539 | G_console->log_event( |
| | 540 | vmg_ OS_EVT_KEY, keyname, strlen(keyname), TRUE); |
| | 541 | } |
| | 542 | |
| | 543 | /* add it to the list */ |
| | 544 | lst->cons_set_element(1, &val); |
| | 545 | |
| | 546 | break; |
| | 547 | |
| | 548 | case OS_EVT_HREF: |
| | 549 | /* create the string for the href text */ |
| | 550 | val.set_obj(str_from_ui_str(vmg_ info.href)); |
| | 551 | |
| | 552 | /* add it to the list */ |
| | 553 | lst->cons_set_element(1, &val); |
| | 554 | |
| | 555 | /* log it */ |
| | 556 | G_console->log_event(vmg_ OS_EVT_HREF, |
| | 557 | info.href, strlen(info.href), FALSE); |
| | 558 | break; |
| | 559 | |
| | 560 | case OS_EVT_COMMAND: |
| | 561 | /* the second element is the command ID code */ |
| | 562 | val.set_int(info.cmd_id); |
| | 563 | lst->cons_set_element(1, &val); |
| | 564 | |
| | 565 | /* log it */ |
| | 566 | { |
| | 567 | char buf[20]; |
| | 568 | sprintf(buf, "%d", info.cmd_id); |
| | 569 | G_console->log_event(vmg_ OS_EVT_COMMAND, |
| | 570 | buf, strlen(buf), TRUE); |
| | 571 | } |
| | 572 | break; |
| | 573 | |
| | 574 | default: |
| | 575 | /* other event types have no extra data */ |
| | 576 | G_console->log_event(vmg_ evt); |
| | 577 | break; |
| | 578 | } |
| | 579 | |
| | 580 | /* return the list */ |
| | 581 | retval_obj(vmg_ lst_obj); |
| | 582 | |
| | 583 | /* we can drop the garbage collection protection now */ |
| | 584 | G_stk->discard(); |
| | 585 | } |
| | 586 | |
| | 587 | /* ------------------------------------------------------------------------ */ |
| | 588 | /* |
| | 589 | * Service routine: Map an "extended" keystroke from raw os_getc_raw() |
| | 590 | * notation to a UTF-8 key name. The caller should pass the second byte of |
| | 591 | * the extended two-byte raw sequence. |
| | 592 | */ |
| | 593 | int CVmBifTIO::map_ext_key(VMG_ char *namebuf, int extc) |
| | 594 | { |
| | 595 | /* |
| | 596 | * Portable key names for the extended keystrokes. We map the extended |
| | 597 | * key codes to these strings, so that the TADS code can access arrow |
| | 598 | * keys and the like. |
| | 599 | */ |
| | 600 | static const char *ext_key_names[] = |
| | 601 | { |
| | 602 | "[up]", /* CMD_UP - 1 */ |
| | 603 | "[down]", /* CMD_DOWN - 2 */ |
| | 604 | "[right]", /* CMD_RIGHT - 3 */ |
| | 605 | "[left]", /* CMD_LEFT - 4 */ |
| | 606 | "[end]", /* CMD_END - 5 */ |
| | 607 | "[home]", /* CMD_HOME - 6 */ |
| | 608 | "[del-eol]", /* CMD_DEOL - 7 */ |
| | 609 | "[del-line]", /* CMD_KILL - 8 */ |
| | 610 | "[del]", /* CMD_DEL - 9 */ |
| | 611 | "[scroll]", /* CMD_SCR - 10 */ |
| | 612 | "[page up]", /* CMD_PGUP - 11 */ |
| | 613 | "[page down]", /* CMD_PGDN - 12 */ |
| | 614 | "[top]", /* CMD_TOP - 13 */ |
| | 615 | "[bottom]", /* CMD_BOT - 14 */ |
| | 616 | "[f1]", /* CMD_F1 - 15 */ |
| | 617 | "[f2]", /* CMD_F2 - 16 */ |
| | 618 | "[f3]", /* CMD_F3 - 17 */ |
| | 619 | "[f4]", /* CMD_F4 - 18 */ |
| | 620 | "[f5]", /* CMD_F5 - 19 */ |
| | 621 | "[f6]", /* CMD_F6 - 20 */ |
| | 622 | "[f7]", /* CMD_F7 - 21 */ |
| | 623 | "[f8]", /* CMD_F8 - 22 */ |
| | 624 | "[f9]", /* CMD_F9 - 23 */ |
| | 625 | "[f10]", /* CMD_F10 - 24 */ |
| | 626 | "[?]", /* invalid key - CMD_CHOME - 25 */ |
| | 627 | "[tab]", /* CMD_TAB - 26 */ |
| | 628 | "[?]", /* invalid key - shift-F2 - 27 */ |
| | 629 | "[?]", /* not used (obsoleted) - 28 */ |
| | 630 | "[word-left]", /* CMD_WORD_LEFT - 29 */ |
| | 631 | "[word-right]", /* CMD_WORD_RIGHT - 30 */ |
| | 632 | "[del-word]", /* CMD_WORDKILL - 31 */ |
| | 633 | "[eof]", /* CMD_EOF - 32 */ |
| | 634 | "[break]" /* CMD_BREAK - 33 */ |
| | 635 | }; |
| | 636 | |
| | 637 | /* if it's in the key name array, use the array entry */ |
| | 638 | if (extc >= 1 |
| | 639 | && extc <= (int)sizeof(ext_key_names)/sizeof(ext_key_names[0])) |
| | 640 | { |
| | 641 | /* use the array name */ |
| | 642 | strcpy(namebuf, ext_key_names[extc - 1]); |
| | 643 | return TRUE; |
| | 644 | } |
| | 645 | |
| | 646 | /* if it's in the ALT key range, generate an ALT key name */ |
| | 647 | if ((unsigned char)extc >= CMD_ALT && (unsigned char)extc <= CMD_ALT + 25) |
| | 648 | { |
| | 649 | /* generate an ALT key name */ |
| | 650 | strcpy(namebuf, "[alt-?]"); |
| | 651 | namebuf[5] = (char)(extc - CMD_ALT + 'a'); |
| | 652 | return TRUE; |
| | 653 | } |
| | 654 | |
| | 655 | /* it's not a valid key - use '[?]' as the name */ |
| | 656 | strcpy(namebuf, "[?]"); |
| | 657 | return FALSE; |
| | 658 | } |
| | 659 | |
| | 660 | /* |
| | 661 | * Service routine: Map a keystroke from the raw notation, consisting of a |
| | 662 | * normal keystroke in the local character set or an extended command key |
| | 663 | * using a CMD_xxx code, to UTF-8. If the keystroke is a control character |
| | 664 | * or any CMD_xxx code, we'll map the key to a high-level keystroke name |
| | 665 | * enclosed in square brackets. |
| | 666 | */ |
| | 667 | int CVmBifTIO::map_raw_key(VMG_ char *namebuf, const char *c, size_t len) |
| | 668 | { |
| | 669 | size_t outlen; |
| | 670 | |
| | 671 | /* if it's a control character, give it a portable key name */ |
| | 672 | if (len == 1 && ((c[0] >= 1 && c[0] <= 27) || c[0] == 127)) |
| | 673 | { |
| | 674 | switch(c[0]) |
| | 675 | { |
| | 676 | case 10: |
| | 677 | case 13: |
| | 678 | /* |
| | 679 | * return an ASCII 10 (regardless of local newline conventions |
| | 680 | * - this is the internal string representation, which we |
| | 681 | * define to use ASCII 10 to represent a newline everywhere) |
| | 682 | */ |
| | 683 | namebuf[0] = 10; |
| | 684 | namebuf[1] = '\0'; |
| | 685 | return TRUE; |
| | 686 | |
| | 687 | case 9: |
| | 688 | /* return ASCII 9 for TAB characters */ |
| | 689 | namebuf[0] = 9; |
| | 690 | namebuf[1] = '\0'; |
| | 691 | return TRUE; |
| | 692 | |
| | 693 | case 8: |
| | 694 | case 127: |
| | 695 | /* return '[bksp]' for backspace/del characters */ |
| | 696 | strcpy(namebuf, "[bksp]"); |
| | 697 | return TRUE; |
| | 698 | |
| | 699 | case 27: |
| | 700 | /* return '[esc]' for the escape key */ |
| | 701 | strcpy(namebuf, "[esc]"); |
| | 702 | return TRUE; |
| | 703 | |
| | 704 | default: |
| | 705 | /* return '[ctrl-X]' for other control characters */ |
| | 706 | strcpy(namebuf, "[ctrl-?]"); |
| | 707 | namebuf[6] = (char)(c[0] + 'a' - 1); |
| | 708 | return TRUE; |
| | 709 | } |
| | 710 | } |
| | 711 | |
| | 712 | /* map the character to wide Unicode */ |
| | 713 | outlen = 32; |
| | 714 | G_cmap_from_ui->map(&namebuf, &outlen, c, len); |
| | 715 | |
| | 716 | /* null-terminate the result */ |
| | 717 | *namebuf = '\0'; |
| | 718 | |
| | 719 | /* successfully mapped */ |
| | 720 | return TRUE; |
| | 721 | } |
| | 722 | |
| | 723 | /* |
| | 724 | * Service routine: determine if a raw byte sequence forms a complete |
| | 725 | * character in the local character set. |
| | 726 | */ |
| | 727 | int CVmBifTIO::raw_key_complete(VMG_ const char *c, size_t len) |
| | 728 | { |
| | 729 | /* ask the local character mapper if it's a complete character */ |
| | 730 | return G_cmap_from_ui->is_complete_char(c, len); |
| | 731 | } |
| | 732 | |
| | 733 | |
| | 734 | /* ------------------------------------------------------------------------ */ |
| | 735 | /* |
| | 736 | * Standard system button labels for bifinpdlg() |
| | 737 | */ |
| | 738 | #define BIFINPDLG_LBL_OK 1 |
| | 739 | #define BIFINPDLG_LBL_CANCEL 2 |
| | 740 | #define BIFINPDLG_LBL_YES 3 |
| | 741 | #define BIFINPDLG_LBL_NO 4 |
| | 742 | |
| | 743 | /* |
| | 744 | * inputdialog - run a dialog |
| | 745 | */ |
| | 746 | void CVmBifTIO::inputdialog(VMG_ uint argc) |
| | 747 | { |
| | 748 | int icon_id; |
| | 749 | char prompt[256]; |
| | 750 | char label_buf[256]; |
| | 751 | vm_val_t label_val[10]; |
| | 752 | const char *labels[10]; |
| | 753 | int std_btns; |
| | 754 | int btn_cnt; |
| | 755 | const char *listp; |
| | 756 | char *dst; |
| | 757 | size_t dstrem; |
| | 758 | int default_resp; |
| | 759 | int cancel_resp; |
| | 760 | int resp; |
| | 761 | char numbuf[32]; |
| | 762 | |
| | 763 | /* check arguments */ |
| | 764 | check_argc(vmg_ argc, 5); |
| | 765 | |
| | 766 | /* get the icon number */ |
| | 767 | icon_id = pop_int_val(vmg0_); |
| | 768 | |
| | 769 | /* get the prompt string */ |
| | 770 | pop_str_val_ui(vmg_ prompt, sizeof(prompt)); |
| | 771 | |
| | 772 | /* there aren't any buttons yet */ |
| | 773 | btn_cnt = 0; |
| | 774 | |
| | 775 | /* check for the button type */ |
| | 776 | if (G_stk->get(0)->typ == VM_INT) |
| | 777 | { |
| | 778 | /* get the standard button set ID */ |
| | 779 | std_btns = pop_int_val(vmg0_); |
| | 780 | } |
| | 781 | else |
| | 782 | { |
| | 783 | size_t i; |
| | 784 | size_t cnt; |
| | 785 | vm_val_t *valp; |
| | 786 | |
| | 787 | /* we're not using any standard button set */ |
| | 788 | std_btns = 0; |
| | 789 | |
| | 790 | /* get the button label list */ |
| | 791 | listp = pop_list_val(vmg0_); |
| | 792 | |
| | 793 | /* |
| | 794 | * run through the list and get the button items into our array |
| | 795 | * (we do this rather than traversing the list directly so that |
| | 796 | * we don't have to worry about a constant list's data being |
| | 797 | * paged out) |
| | 798 | */ |
| | 799 | cnt = vmb_get_len(listp); |
| | 800 | |
| | 801 | /* limit the number of elements to our private array size */ |
| | 802 | if (cnt > sizeof(label_val)/sizeof(label_val[0])) |
| | 803 | cnt = sizeof(label_val)/sizeof(label_val[0]); |
| | 804 | |
| | 805 | /* skip the list length prefix */ |
| | 806 | listp += VMB_LEN; |
| | 807 | |
| | 808 | /* copy the list */ |
| | 809 | for (i = cnt, valp = label_val ; i > 0 ; |
| | 810 | --i, listp += VMB_DATAHOLDER, ++valp) |
| | 811 | { |
| | 812 | /* get this element into our array */ |
| | 813 | vmb_get_dh(listp, valp); |
| | 814 | } |
| | 815 | |
| | 816 | /* set up to write into our label buffer */ |
| | 817 | dst = label_buf; |
| | 818 | dstrem = sizeof(label_buf); |
| | 819 | |
| | 820 | /* now build our internal button list from the array elements */ |
| | 821 | for (i = 0, valp = label_val ; i < cnt ; ++i, ++valp) |
| | 822 | { |
| | 823 | const char *p; |
| | 824 | |
| | 825 | /* |
| | 826 | * We could have a number or a string in each element. If |
| | 827 | * the element is a number, it refers to a standard label. |
| | 828 | * If it's a string, use the string directly. |
| | 829 | */ |
| | 830 | if ((p = valp->get_as_string(vmg0_)) != 0) |
| | 831 | { |
| | 832 | size_t copy_len; |
| | 833 | |
| | 834 | /* |
| | 835 | * it's a string - make a copy in the label buffer, |
| | 836 | * making sure to leave space for null termination |
| | 837 | */ |
| | 838 | copy_len = vmb_get_len(p); |
| | 839 | if (copy_len > dstrem - 1) |
| | 840 | copy_len = utf8_ptr::s_trunc(p + VMB_LEN, dstrem - 1); |
| | 841 | memcpy(dst, p + VMB_LEN, copy_len); |
| | 842 | |
| | 843 | /* null-terminate the buffer */ |
| | 844 | dst[copy_len++] = '\0'; |
| | 845 | |
| | 846 | /* set this button to point to the converted text */ |
| | 847 | labels[btn_cnt++] = dst; |
| | 848 | |
| | 849 | /* skip past this label */ |
| | 850 | dst += copy_len; |
| | 851 | dstrem -= copy_len; |
| | 852 | } |
| | 853 | else if (valp->typ == VM_INT) |
| | 854 | { |
| | 855 | int id; |
| | 856 | int resid; |
| | 857 | char rscbuf[128]; |
| | 858 | |
| | 859 | /* it's a standard system label ID - get the ID */ |
| | 860 | id = (int)valp->val.intval; |
| | 861 | |
| | 862 | /* translate it to the appropriate string resource */ |
| | 863 | switch(id) |
| | 864 | { |
| | 865 | case BIFINPDLG_LBL_OK: |
| | 866 | resid = VMRESID_BTN_OK; |
| | 867 | break; |
| | 868 | |
| | 869 | case BIFINPDLG_LBL_CANCEL: |
| | 870 | resid = VMRESID_BTN_CANCEL; |
| | 871 | break; |
| | 872 | |
| | 873 | case BIFINPDLG_LBL_YES: |
| | 874 | resid = VMRESID_BTN_YES; |
| | 875 | break; |
| | 876 | |
| | 877 | case BIFINPDLG_LBL_NO: |
| | 878 | resid = VMRESID_BTN_NO; |
| | 879 | break; |
| | 880 | |
| | 881 | default: |
| | 882 | resid = 0; |
| | 883 | break; |
| | 884 | } |
| | 885 | |
| | 886 | /* |
| | 887 | * if we got a valid resource ID, load the resource; |
| | 888 | * otherwise, skip this button |
| | 889 | */ |
| | 890 | if (resid != 0 |
| | 891 | && !os_get_str_rsc(resid, rscbuf, sizeof(rscbuf))) |
| | 892 | { |
| | 893 | /* set this button to point to the converted text */ |
| | 894 | labels[btn_cnt++] = dst; |
| | 895 | |
| | 896 | /* convert the resource text to UTF-8 */ |
| | 897 | G_cmap_from_ui->map(&dst, &dstrem, |
| | 898 | rscbuf, strlen(rscbuf)); |
| | 899 | |
| | 900 | /* null-terminate the converted text */ |
| | 901 | *dst++ = '\0'; |
| | 902 | --dstrem; |
| | 903 | } |
| | 904 | } |
| | 905 | } |
| | 906 | } |
| | 907 | |
| | 908 | /* get the default response */ |
| | 909 | if (G_stk->get(0)->typ == VM_NIL) |
| | 910 | { |
| | 911 | /* discard the nil argument */ |
| | 912 | G_stk->discard(); |
| | 913 | |
| | 914 | /* there's no default response */ |
| | 915 | default_resp = 0; |
| | 916 | } |
| | 917 | else |
| | 918 | { |
| | 919 | /* get the default response index */ |
| | 920 | default_resp = pop_int_val(vmg0_); |
| | 921 | } |
| | 922 | |
| | 923 | /* get the cancel response */ |
| | 924 | if (G_stk->get(0)->typ == VM_NIL) |
| | 925 | { |
| | 926 | /* discard the nil argument */ |
| | 927 | G_stk->discard(); |
| | 928 | |
| | 929 | /* there's no cancel response */ |
| | 930 | cancel_resp = 0; |
| | 931 | } |
| | 932 | else |
| | 933 | { |
| | 934 | /* get the cancel response index */ |
| | 935 | cancel_resp = pop_int_val(vmg0_); |
| | 936 | } |
| | 937 | |
| | 938 | /* check for script input */ |
| | 939 | static int filter[] = { VMCON_EVT_DIALOG }; |
| | 940 | int evt; |
| | 941 | if (G_console->read_event_script( |
| | 942 | vmg_ &evt, numbuf, sizeof(numbuf), |
| | 943 | filter, sizeof(filter)/sizeof(filter[0]), 0)) |
| | 944 | { |
| | 945 | /* we got a script response - no need to show the dialog */ |
| | 946 | resp = atoi(numbuf); |
| | 947 | |
| | 948 | /* log the event */ |
| | 949 | G_console->log_event(vmg_ VMCON_EVT_DIALOG, |
| | 950 | numbuf, strlen(numbuf), FALSE); |
| | 951 | } |
| | 952 | else |
| | 953 | { |
| | 954 | /* flush output before showing the dialog */ |
| | 955 | G_console->flush_all(vmg_ VM_NL_INPUT); |
| | 956 | |
| | 957 | /* show the dialog */ |
| | 958 | resp = G_console->input_dialog(vmg_ icon_id, prompt, |
| | 959 | std_btns, labels, btn_cnt, |
| | 960 | default_resp, cancel_resp); |
| | 961 | |
| | 962 | /* log the event */ |
| | 963 | sprintf(numbuf, "%d", resp); |
| | 964 | G_console->log_event(vmg_ VMCON_EVT_DIALOG, |
| | 965 | numbuf, strlen(numbuf), TRUE); |
| | 966 | } |
| | 967 | |
| | 968 | /* return the result */ |
| | 969 | retval_int(vmg_ resp); |
| | 970 | } |
| | 971 | |
| | 972 | /* ------------------------------------------------------------------------ */ |
| | 973 | /* |
| | 974 | * askfile - ask for a filename via a standard file dialog |
| | 975 | */ |
| | 976 | void CVmBifTIO::askfile(VMG_ uint argc) |
| | 977 | { |
| | 978 | char prompt[256]; |
| | 979 | int dialog_type; |
| | 980 | os_filetype_t file_type; |
| | 981 | long flags; |
| | 982 | int result; |
| | 983 | char fname[OSFNMAX*3 + 1]; |
| | 984 | vm_obj_id_t lst_obj; |
| | 985 | CVmObjList *lst; |
| | 986 | vm_val_t val; |
| | 987 | int from_script = FALSE; |
| | 988 | |
| | 989 | /* check arguments */ |
| | 990 | check_argc(vmg_ argc, 4); |
| | 991 | |
| | 992 | /* get the prompt string */ |
| | 993 | pop_str_val_ui(vmg_ prompt, sizeof(prompt)); |
| | 994 | |
| | 995 | /* get the dialog type and file type */ |
| | 996 | dialog_type = pop_int_val(vmg0_); |
| | 997 | file_type = (os_filetype_t)pop_int_val(vmg0_); |
| | 998 | |
| | 999 | /* pop the flags */ |
| | 1000 | flags = pop_long_val(vmg0_); |
| | 1001 | |
| | 1002 | /* check for a script response */ |
| | 1003 | static int filter[] = { VMCON_EVT_FILE }; |
| | 1004 | int evt; |
| | 1005 | unsigned long attrs; |
| | 1006 | if (G_console->read_event_script( |
| | 1007 | vmg_ &evt, fname, sizeof(fname), |
| | 1008 | filter, sizeof(filter)/sizeof(filter[0]), &attrs)) |
| | 1009 | { |
| | 1010 | char prompt[OSFNMAX + 255]; |
| | 1011 | int ok = TRUE; |
| | 1012 | |
| | 1013 | /* we got a response from the script */ |
| | 1014 | from_script = TRUE; |
| | 1015 | result = (fname[0] != '\0' ? OS_AFE_SUCCESS : OS_AFE_CANCEL); |
| | 1016 | |
| | 1017 | /* |
| | 1018 | * If this is a "save" prompt, and the OVERWRITE flag isn't |
| | 1019 | * provided, and the file already exists, show an interactive |
| | 1020 | * warning that we're about to ovewrite the file. |
| | 1021 | */ |
| | 1022 | if (dialog_type == OS_AFP_SAVE |
| | 1023 | && result == OS_AFE_SUCCESS |
| | 1024 | && (attrs & VMCON_EVTATTR_OVERWRITE) == 0 |
| | 1025 | && !osfacc(fname)) |
| | 1026 | { |
| | 1027 | /* the file exists - warn about the overwrite */ |
| | 1028 | ok = FALSE; |
| | 1029 | sprintf(prompt, "The script might overwrite the file %s. ", fname); |
| | 1030 | } |
| | 1031 | |
| | 1032 | /* |
| | 1033 | * If this is a "save" prompt, AND the file doesn't already exist, |
| | 1034 | * try creating the file to see if we can - this will test to see |
| | 1035 | * if the target directory exists and is writable, for instance. |
| | 1036 | */ |
| | 1037 | if (ok |
| | 1038 | && dialog_type == OS_AFP_SAVE |
| | 1039 | && result == OS_AFE_SUCCESS |
| | 1040 | && osfacc(fname)) |
| | 1041 | { |
| | 1042 | /* try creating the file */ |
| | 1043 | osfildef *fp = osfopwb(fname, file_type); |
| | 1044 | |
| | 1045 | /* if that succeeded, undo the creation; otherwise warn */ |
| | 1046 | if (fp != 0) |
| | 1047 | { |
| | 1048 | /* it worked - close and delete the test file */ |
| | 1049 | osfcls(fp); |
| | 1050 | osfdel(fname); |
| | 1051 | } |
| | 1052 | else |
| | 1053 | { |
| | 1054 | /* didn't work - warn about it */ |
| | 1055 | ok = FALSE; |
| | 1056 | sprintf(prompt, "The script is attempting to create file %s, " |
| | 1057 | "but that file cannot be created.", fname); |
| | 1058 | } |
| | 1059 | } |
| | 1060 | |
| | 1061 | /* |
| | 1062 | * If this is an "open" prompt, and the file isn't readable, warn |
| | 1063 | * about it. |
| | 1064 | */ |
| | 1065 | if (ok |
| | 1066 | && dialog_type == OS_AFP_OPEN |
| | 1067 | && result == OS_AFE_SUCCESS |
| | 1068 | && osfacc(fname)) |
| | 1069 | { |
| | 1070 | ok = FALSE; |
| | 1071 | sprintf(prompt, "The script is attempting to open file %s, " |
| | 1072 | "but this file doesn't exist or isn't readable.", fname); |
| | 1073 | } |
| | 1074 | |
| | 1075 | /* check to see if we're warning about anything */ |
| | 1076 | if (!ok) |
| | 1077 | { |
| | 1078 | char fullprompt[OSFNMAX + 255 + 150]; |
| | 1079 | |
| | 1080 | /* build the full prompt */ |
| | 1081 | sprintf(fullprompt, "%s Do you wish to proceed? Select Yes to " |
| | 1082 | "proceed with this file, No to choose a different file, " |
| | 1083 | "or Cancel to stop script playback.", prompt); |
| | 1084 | |
| | 1085 | /* |
| | 1086 | * display a dialog - note that this goes directly to user, |
| | 1087 | * bypassing the active script, since this is a question about |
| | 1088 | * how to handle a problem in the script |
| | 1089 | */ |
| | 1090 | switch (G_console->input_dialog( |
| | 1091 | vmg_ OS_INDLG_ICON_WARNING, fullprompt, |
| | 1092 | OS_INDLG_YESNOCANCEL, 0, 0, 2, 3)) |
| | 1093 | { |
| | 1094 | case 1: |
| | 1095 | /* yes - proceed with fname */ |
| | 1096 | break; |
| | 1097 | |
| | 1098 | case 2: |
| | 1099 | /* no - ask for a new file */ |
| | 1100 | result = G_console->askfile( |
| | 1101 | vmg_ prompt, strlen(prompt), |
| | 1102 | fname, sizeof(fname), dialog_type, file_type); |
| | 1103 | |
| | 1104 | /* this didn't come from the script after all */ |
| | 1105 | from_script = FALSE; |
| | 1106 | |
| | 1107 | /* if they canceled, cancel the whole script playback */ |
| | 1108 | if (result != OS_AFE_SUCCESS) |
| | 1109 | close_script_file(vmg0_); |
| | 1110 | |
| | 1111 | /* handled */ |
| | 1112 | break; |
| | 1113 | |
| | 1114 | case 3: |
| | 1115 | /* cancel - stop the script playback */ |
| | 1116 | close_script_file(vmg0_); |
| | 1117 | |
| | 1118 | /* indicate cancellation */ |
| | 1119 | result = OS_AFE_CANCEL; |
| | 1120 | break; |
| | 1121 | } |
| | 1122 | } |
| | 1123 | } |
| | 1124 | else |
| | 1125 | { |
| | 1126 | /* ask for a file via the UI */ |
| | 1127 | result = G_console->askfile( |
| | 1128 | vmg_ prompt, strlen(prompt), |
| | 1129 | fname, sizeof(fname), dialog_type, file_type); |
| | 1130 | } |
| | 1131 | |
| | 1132 | /* |
| | 1133 | * Allocate a list to store the return value. If we successfully |
| | 1134 | * got a filename, we need a two-element list - one element for the |
| | 1135 | * success code and another for the string with the filename. If we |
| | 1136 | * didn't succeed in getting the filename, we only need a single |
| | 1137 | * element, which will contain the error code. |
| | 1138 | */ |
| | 1139 | lst_obj = CVmObjList::create(vmg_ FALSE, |
| | 1140 | result == OS_AFE_SUCCESS ? 2 : 1); |
| | 1141 | lst = (CVmObjList *)vm_objp(vmg_ lst_obj); |
| | 1142 | |
| | 1143 | /* save it on the stack as protection against garbage collection */ |
| | 1144 | val.set_obj(lst_obj); |
| | 1145 | G_stk->push(&val); |
| | 1146 | |
| | 1147 | /* set the first element to the result code */ |
| | 1148 | val.set_int(result); |
| | 1149 | lst->cons_set_element(0, &val); |
| | 1150 | |
| | 1151 | /* if we got a filename, set the second element to the filename string */ |
| | 1152 | if (result == OS_AFE_SUCCESS) |
| | 1153 | { |
| | 1154 | /* |
| | 1155 | * Create a string for the filename. If it's coming from a script, |
| | 1156 | * we need to translate it to the local character set; otherwise |
| | 1157 | * it's already in UTF-8. |
| | 1158 | */ |
| | 1159 | val.set_obj( |
| | 1160 | from_script |
| | 1161 | ? str_from_ui_str(vmg_ fname) |
| | 1162 | : CVmObjString::create(vmg_ FALSE, fname, strlen(fname))); |
| | 1163 | |
| | 1164 | /* store the string as the second list element */ |
| | 1165 | lst->cons_set_element(1, &val); |
| | 1166 | } |
| | 1167 | |
| | 1168 | /* log the event */ |
| | 1169 | if (result == OS_AFE_SUCCESS) |
| | 1170 | G_console->log_event(vmg_ VMCON_EVT_FILE, |
| | 1171 | fname, strlen(fname), FALSE); |
| | 1172 | else |
| | 1173 | G_console->log_event(vmg_ VMCON_EVT_FILE); |
| | 1174 | |
| | 1175 | /* return the list */ |
| | 1176 | retval_obj(vmg_ lst_obj); |
| | 1177 | |
| | 1178 | /* we no longer need the garbage collector protection */ |
| | 1179 | G_stk->discard(); |
| | 1180 | } |
| | 1181 | |
| | 1182 | |
| | 1183 | /* ------------------------------------------------------------------------ */ |
| | 1184 | /* |
| | 1185 | * timeDelay - pause for a specified interval |
| | 1186 | */ |
| | 1187 | void CVmBifTIO::timedelay(VMG_ uint argc) |
| | 1188 | { |
| | 1189 | long delay_ms; |
| | 1190 | |
| | 1191 | /* check arguments */ |
| | 1192 | check_argc(vmg_ argc, 1); |
| | 1193 | |
| | 1194 | /* get the delay time in milliseconds */ |
| | 1195 | delay_ms = pop_long_val(vmg0_); |
| | 1196 | |
| | 1197 | /* flush any pending output */ |
| | 1198 | G_console->flush_all(vmg_ VM_NL_NONE); |
| | 1199 | |
| | 1200 | /* ask the system code to pause */ |
| | 1201 | os_sleep_ms(delay_ms); |
| | 1202 | } |
| | 1203 | |
| | 1204 | /* ------------------------------------------------------------------------ */ |
| | 1205 | /* |
| | 1206 | * systemInfo |
| | 1207 | */ |
| | 1208 | void CVmBifTIO::sysinfo(VMG_ uint argc) |
| | 1209 | { |
| | 1210 | int info; |
| | 1211 | long result; |
| | 1212 | |
| | 1213 | /* make sure we have at least one argument */ |
| | 1214 | if (argc < 1) |
| | 1215 | err_throw(VMERR_WRONG_NUM_OF_ARGS); |
| | 1216 | |
| | 1217 | /* get the information type code */ |
| | 1218 | info = pop_int_val(vmg0_); |
| | 1219 | |
| | 1220 | /* see what we have */ |
| | 1221 | switch(info) |
| | 1222 | { |
| | 1223 | case SYSINFO_SYSINFO: |
| | 1224 | /* there are no additional arguments for this information type */ |
| | 1225 | check_argc(vmg_ argc, 1); |
| | 1226 | |
| | 1227 | /* system information is supported in this version - return true */ |
| | 1228 | retval_true(vmg0_); |
| | 1229 | break; |
| | 1230 | |
| | 1231 | case SYSINFO_VERSION: |
| | 1232 | /* there are no additional arguments for this information type */ |
| | 1233 | check_argc(vmg_ argc, 1); |
| | 1234 | |
| | 1235 | /* return the VM version string, formatted as a string */ |
| | 1236 | { |
| | 1237 | char buf[30]; |
| | 1238 | |
| | 1239 | sprintf(buf, "%d.%d.%d", |
| | 1240 | (int)((T3VM_VSN_NUMBER >> 16) & 0xffff), |
| | 1241 | (int)((T3VM_VSN_NUMBER >> 8) & 0xff), |
| | 1242 | (int)(T3VM_VSN_NUMBER & 0xff)); |
| | 1243 | retval_str(vmg_ buf); |
| | 1244 | } |
| | 1245 | break; |
| | 1246 | |
| | 1247 | case SYSINFO_OS_NAME: |
| | 1248 | /* there are no additional arguments for this information type */ |
| | 1249 | check_argc(vmg_ argc, 1); |
| | 1250 | |
| | 1251 | /* return the OS name as a string */ |
| | 1252 | retval_str(vmg_ OS_SYSTEM_NAME); |
| | 1253 | break; |
| | 1254 | |
| | 1255 | case SYSINFO_HTML: |
| | 1256 | case SYSINFO_JPEG: |
| | 1257 | case SYSINFO_PNG: |
| | 1258 | case SYSINFO_WAV: |
| | 1259 | case SYSINFO_MIDI: |
| | 1260 | case SYSINFO_WAV_MIDI_OVL: |
| | 1261 | case SYSINFO_WAV_OVL: |
| | 1262 | case SYSINFO_PREF_IMAGES: |
| | 1263 | case SYSINFO_PREF_SOUNDS: |
| | 1264 | case SYSINFO_PREF_MUSIC: |
| | 1265 | case SYSINFO_PREF_LINKS: |
| | 1266 | case SYSINFO_MPEG: |
| | 1267 | case SYSINFO_MPEG1: |
| | 1268 | case SYSINFO_MPEG2: |
| | 1269 | case SYSINFO_MPEG3: |
| | 1270 | case SYSINFO_LINKS_HTTP: |
| | 1271 | case SYSINFO_LINKS_FTP: |
| | 1272 | case SYSINFO_LINKS_NEWS: |
| | 1273 | case SYSINFO_LINKS_MAILTO: |
| | 1274 | case SYSINFO_LINKS_TELNET: |
| | 1275 | case SYSINFO_PNG_TRANS: |
| | 1276 | case SYSINFO_PNG_ALPHA: |
| | 1277 | case SYSINFO_OGG: |
| | 1278 | case SYSINFO_MNG: |
| | 1279 | case SYSINFO_MNG_TRANS: |
| | 1280 | case SYSINFO_MNG_ALPHA: |
| | 1281 | case SYSINFO_TEXT_COLORS: |
| | 1282 | case SYSINFO_TEXT_HILITE: |
| | 1283 | case SYSINFO_BANNERS: |
| | 1284 | case SYSINFO_INTERP_CLASS: |
| | 1285 | /* there are no additional arguments for these information types */ |
| | 1286 | check_argc(vmg_ argc, 1); |
| | 1287 | |
| | 1288 | /* ask the OS layer for the information */ |
| | 1289 | if (os_get_sysinfo(info, 0, &result)) |
| | 1290 | { |
| | 1291 | /* we got a valid result - return it */ |
| | 1292 | retval_int(vmg_ result); |
| | 1293 | } |
| | 1294 | else |
| | 1295 | { |
| | 1296 | /* |
| | 1297 | * the information type is not known to the OS layer - |
| | 1298 | * return nil to indicate that the information isn't |
| | 1299 | * available |
| | 1300 | */ |
| | 1301 | retval_nil(vmg0_); |
| | 1302 | } |
| | 1303 | break; |
| | 1304 | |
| | 1305 | case SYSINFO_HTML_MODE: |
| | 1306 | /* |
| | 1307 | * This sysinfo flag is explicitly not used in TADS 3, since we're |
| | 1308 | * always in HTML mode. (We make this case explicit to call |
| | 1309 | * attention to the fact that it was not accidentally omitted, but |
| | 1310 | * is intentionally not used.) |
| | 1311 | */ |
| | 1312 | /* fall through to default case */ |
| | 1313 | |
| | 1314 | default: |
| | 1315 | /* |
| | 1316 | * Other codes fail harmlessly with a nil return value. Pop all |
| | 1317 | * remaining arguments and return nil. (Note that we discard |
| | 1318 | * only (argc-1) arguments because we've already popped the |
| | 1319 | * first argument.) |
| | 1320 | */ |
| | 1321 | G_stk->discard(argc - 1); |
| | 1322 | retval_nil(vmg0_); |
| | 1323 | break; |
| | 1324 | } |
| | 1325 | } |
| | 1326 | |
| | 1327 | /* ------------------------------------------------------------------------ */ |
| | 1328 | /* |
| | 1329 | * status_mode - set the status line mode |
| | 1330 | */ |
| | 1331 | void CVmBifTIO::status_mode(VMG_ uint argc) |
| | 1332 | { |
| | 1333 | int mode; |
| | 1334 | |
| | 1335 | /* check arguments */ |
| | 1336 | check_argc(vmg_ argc, 1); |
| | 1337 | |
| | 1338 | /* pop the mode value */ |
| | 1339 | mode = pop_int_val(vmg0_); |
| | 1340 | |
| | 1341 | /* set the new status mode in the console */ |
| | 1342 | G_console->set_statusline_mode(vmg_ mode); |
| | 1343 | } |
| | 1344 | |
| | 1345 | /* ------------------------------------------------------------------------ */ |
| | 1346 | /* |
| | 1347 | * status_right - set the string in the right half of the status line |
| | 1348 | */ |
| | 1349 | void CVmBifTIO::status_right(VMG_ uint argc) |
| | 1350 | { |
| | 1351 | char msg[256]; |
| | 1352 | |
| | 1353 | /* check arguments */ |
| | 1354 | check_argc(vmg_ argc, 1); |
| | 1355 | |
| | 1356 | /* pop the status string */ |
| | 1357 | pop_str_val_ui(vmg_ msg, sizeof(msg)); |
| | 1358 | |
| | 1359 | /* set the string */ |
| | 1360 | os_strsc(msg); |
| | 1361 | } |
| | 1362 | |
| | 1363 | /* ------------------------------------------------------------------------ */ |
| | 1364 | /* |
| | 1365 | * res_exists - check to see if an external resource can be loaded |
| | 1366 | * through the host application |
| | 1367 | */ |
| | 1368 | void CVmBifTIO::res_exists(VMG_ uint argc) |
| | 1369 | { |
| | 1370 | const char *res_name; |
| | 1371 | int result; |
| | 1372 | |
| | 1373 | /* check arguments */ |
| | 1374 | check_argc(vmg_ argc, 1); |
| | 1375 | |
| | 1376 | /* pop the resource name */ |
| | 1377 | res_name = pop_str_val(vmg0_); |
| | 1378 | |
| | 1379 | /* ask the host application if the resource can be loaded */ |
| | 1380 | result = G_host_ifc->resfile_exists(res_name + VMB_LEN, osrp2(res_name)); |
| | 1381 | |
| | 1382 | /* return the result */ |
| | 1383 | retval_bool(vmg_ result); |
| | 1384 | } |
| | 1385 | |
| | 1386 | /* ------------------------------------------------------------------------ */ |
| | 1387 | /* |
| | 1388 | * set_script_file flags |
| | 1389 | */ |
| | 1390 | |
| | 1391 | /* read in 'quiet' mode - do not dipslay output while reading the script */ |
| | 1392 | #define VMBIFTADS_SCRIPT_QUIET 0x0001 |
| | 1393 | |
| | 1394 | /* turn off 'more' mode while reading the script */ |
| | 1395 | #define VMBIFTADS_SCRIPT_NONSTOP 0x0002 |
| | 1396 | |
| | 1397 | /* the script is an "event" script - this is a query-only flag */ |
| | 1398 | #define VMBIFTADS_SCRIPT_EVENT 0x0004 |
| | 1399 | |
| | 1400 | /* |
| | 1401 | * set_script_file special request codes |
| | 1402 | */ |
| | 1403 | #define VMBIFTADS_SCRIPTREQ_GET_STATUS 0x7000 |
| | 1404 | |
| | 1405 | |
| | 1406 | /* |
| | 1407 | * set_script_file - open a command input scripting file |
| | 1408 | */ |
| | 1409 | void CVmBifTIO::set_script_file(VMG_ uint argc) |
| | 1410 | { |
| | 1411 | char fname[OSFNMAX]; |
| | 1412 | int flags; |
| | 1413 | |
| | 1414 | /* check arguments */ |
| | 1415 | check_argc_range(vmg_ argc, 1, 2); |
| | 1416 | |
| | 1417 | /* |
| | 1418 | * If the filename is nil, close the current script file. If the |
| | 1419 | * "filename" is a number, it's a special request. Otherwise, the |
| | 1420 | * filename must be a string giving the name of the file to open. |
| | 1421 | */ |
| | 1422 | if (G_stk->get(0)->typ == VM_NIL) |
| | 1423 | { |
| | 1424 | /* discard the nil filename */ |
| | 1425 | G_stk->discard(); |
| | 1426 | |
| | 1427 | /* pop the flags if present - they're superfluous in this case */ |
| | 1428 | if (argc >= 2) |
| | 1429 | G_stk->discard(); |
| | 1430 | |
| | 1431 | /* close the script file */ |
| | 1432 | close_script_file(vmg0_); |
| | 1433 | } |
| | 1434 | else if (G_stk->get(0)->typ == VM_INT) |
| | 1435 | { |
| | 1436 | /* get the request code */ |
| | 1437 | flags = pop_int_val(vmg0_); |
| | 1438 | |
| | 1439 | /* any additional argument is superfluous in this case */ |
| | 1440 | if (argc >= 2) |
| | 1441 | G_stk->discard(); |
| | 1442 | |
| | 1443 | /* check the request */ |
| | 1444 | switch (flags) |
| | 1445 | { |
| | 1446 | case VMBIFTADS_SCRIPTREQ_GET_STATUS: |
| | 1447 | /* get the current script reading status */ |
| | 1448 | if (G_console->is_reading_script()) |
| | 1449 | { |
| | 1450 | /* a script is in progress - return the script flags */ |
| | 1451 | retval_int(vmg_ |
| | 1452 | (G_console->is_quiet_script() |
| | 1453 | ? VMBIFTADS_SCRIPT_QUIET : 0) |
| | 1454 | | (G_console->is_moremode_script() |
| | 1455 | ? 0 : VMBIFTADS_SCRIPT_NONSTOP) |
| | 1456 | | (G_console->is_event_script() |
| | 1457 | ? VMBIFTADS_SCRIPT_EVENT : 0)); |
| | 1458 | } |
| | 1459 | else |
| | 1460 | { |
| | 1461 | /* not reading a script - return nil */ |
| | 1462 | retval_nil(vmg0_); |
| | 1463 | } |
| | 1464 | break; |
| | 1465 | } |
| | 1466 | } |
| | 1467 | else |
| | 1468 | { |
| | 1469 | /* |
| | 1470 | * get the filename string (converted to the file system |
| | 1471 | * character set) |
| | 1472 | */ |
| | 1473 | pop_str_val_fname(vmg_ fname, sizeof(fname)); |
| | 1474 | |
| | 1475 | /* if they provided flags, pop the flags */ |
| | 1476 | flags = 0; |
| | 1477 | if (argc >= 2) |
| | 1478 | flags = pop_int_val(vmg0_); |
| | 1479 | |
| | 1480 | /* open the script file */ |
| | 1481 | G_console->open_script_file(fname, |
| | 1482 | (flags & VMBIFTADS_SCRIPT_QUIET) != 0, |
| | 1483 | !(flags & VMBIFTADS_SCRIPT_NONSTOP)); |
| | 1484 | } |
| | 1485 | } |
| | 1486 | |
| | 1487 | /* |
| | 1488 | * close the script file |
| | 1489 | */ |
| | 1490 | void CVmBifTIO::close_script_file(VMG0_) |
| | 1491 | { |
| | 1492 | int old_more_mode; |
| | 1493 | |
| | 1494 | /* close the script */ |
| | 1495 | old_more_mode = G_console->close_script_file(); |
| | 1496 | |
| | 1497 | /* restore the MORE mode in effect when the script was opened */ |
| | 1498 | G_console->set_more_state(old_more_mode); |
| | 1499 | } |
| | 1500 | |
| | 1501 | /* ------------------------------------------------------------------------ */ |
| | 1502 | /* |
| | 1503 | * get_charset selectors |
| | 1504 | */ |
| | 1505 | |
| | 1506 | /* display character set */ |
| | 1507 | #define VMBIFTADS_CHARSET_DISPLAY 0x0001 |
| | 1508 | |
| | 1509 | /* file system character set for filenames */ |
| | 1510 | #define VMBIFTADS_CHARSET_FILENAME 0x0002 |
| | 1511 | |
| | 1512 | /* typical character set for text file contents */ |
| | 1513 | #define VMBIFTADS_CHARSET_FILECONTENTS 0x0003 |
| | 1514 | |
| | 1515 | /* |
| | 1516 | * get_charset - get a local character set name |
| | 1517 | */ |
| | 1518 | void CVmBifTIO::get_charset(VMG_ uint argc) |
| | 1519 | { |
| | 1520 | char csname[32]; |
| | 1521 | int which; |
| | 1522 | |
| | 1523 | /* check arguments */ |
| | 1524 | check_argc(vmg_ argc, 1); |
| | 1525 | |
| | 1526 | /* get the character set selector */ |
| | 1527 | which = pop_int_val(vmg0_); |
| | 1528 | |
| | 1529 | /* map the selector to the appropriate value */ |
| | 1530 | switch(which) |
| | 1531 | { |
| | 1532 | case VMBIFTADS_CHARSET_DISPLAY: |
| | 1533 | /* |
| | 1534 | * if there was an explicit character set parameter specified at |
| | 1535 | * start-up time, use that |
| | 1536 | */ |
| | 1537 | if (G_disp_cset_name != 0) |
| | 1538 | { |
| | 1539 | /* there's an explicit parameter - return it */ |
| | 1540 | retval_str(vmg_ G_disp_cset_name); |
| | 1541 | |
| | 1542 | /* we're done */ |
| | 1543 | return; |
| | 1544 | } |
| | 1545 | |
| | 1546 | /* no explicit setting - use the OS default character set */ |
| | 1547 | which = OS_CHARMAP_DISPLAY; |
| | 1548 | break; |
| | 1549 | |
| | 1550 | case VMBIFTADS_CHARSET_FILENAME: |
| | 1551 | which = OS_CHARMAP_FILENAME; |
| | 1552 | break; |
| | 1553 | |
| | 1554 | case VMBIFTADS_CHARSET_FILECONTENTS: |
| | 1555 | which = OS_CHARMAP_FILECONTENTS; |
| | 1556 | break; |
| | 1557 | |
| | 1558 | default: |
| | 1559 | /* others are unrecognized; simply return nil for these */ |
| | 1560 | retval_nil(vmg0_); |
| | 1561 | return; |
| | 1562 | } |
| | 1563 | |
| | 1564 | /* get the character set */ |
| | 1565 | os_get_charmap(csname, which); |
| | 1566 | |
| | 1567 | /* return a string with the name */ |
| | 1568 | retval_str(vmg_ csname); |
| | 1569 | } |
| | 1570 | |
| | 1571 | /* ------------------------------------------------------------------------ */ |
| | 1572 | /* |
| | 1573 | * flush_output - flush the display output |
| | 1574 | */ |
| | 1575 | void CVmBifTIO::flush_output(VMG_ uint argc) |
| | 1576 | { |
| | 1577 | /* we take no arguments */ |
| | 1578 | check_argc(vmg_ argc, 0); |
| | 1579 | |
| | 1580 | /* flush output */ |
| | 1581 | G_console->flush(vmg_ VM_NL_NONE); |
| | 1582 | |
| | 1583 | /* immediately update the display */ |
| | 1584 | G_console->update_display(vmg0_); |
| | 1585 | } |
| | 1586 | |
| | 1587 | /* ------------------------------------------------------------------------ */ |
| | 1588 | /* |
| | 1589 | * input_timeout - get a line of input from the keyboard, with an optional |
| | 1590 | * timeout |
| | 1591 | */ |
| | 1592 | void CVmBifTIO::input_timeout(VMG_ uint argc) |
| | 1593 | { |
| | 1594 | char buf[256]; |
| | 1595 | long timeout; |
| | 1596 | int use_timeout; |
| | 1597 | int evt; |
| | 1598 | int ele_count; |
| | 1599 | vm_obj_id_t lst_obj; |
| | 1600 | CVmObjList *lst; |
| | 1601 | vm_val_t val; |
| | 1602 | |
| | 1603 | /* check arguments */ |
| | 1604 | check_argc_range(vmg_ argc, 0, 1); |
| | 1605 | |
| | 1606 | /* if there's a timeout argument, retrieve it */ |
| | 1607 | if (argc == 0) |
| | 1608 | { |
| | 1609 | /* no arguments - there's no timeout */ |
| | 1610 | use_timeout = FALSE; |
| | 1611 | timeout = 0; |
| | 1612 | } |
| | 1613 | else if (G_stk->get(0)->typ == VM_NIL) |
| | 1614 | { |
| | 1615 | /* |
| | 1616 | * there's a timeout argument, but it's nil, so this means there's |
| | 1617 | * no timeout |
| | 1618 | */ |
| | 1619 | use_timeout = FALSE; |
| | 1620 | timeout = 0; |
| | 1621 | |
| | 1622 | /* discard the argument */ |
| | 1623 | G_stk->discard(); |
| | 1624 | } |
| | 1625 | else |
| | 1626 | { |
| | 1627 | /* we have a timeout specified */ |
| | 1628 | use_timeout = TRUE; |
| | 1629 | timeout = pop_long_val(vmg0_); |
| | 1630 | } |
| | 1631 | |
| | 1632 | /* read a line of text from the keyboard */ |
| | 1633 | evt = G_console->read_line_timeout(vmg_ buf, sizeof(buf), |
| | 1634 | timeout, use_timeout); |
| | 1635 | |
| | 1636 | /* figure out how big a list we'll return */ |
| | 1637 | switch(evt) |
| | 1638 | { |
| | 1639 | case OS_EVT_LINE: |
| | 1640 | case OS_EVT_TIMEOUT: |
| | 1641 | /* two elements - the event type, and the line of text */ |
| | 1642 | ele_count = 2; |
| | 1643 | break; |
| | 1644 | |
| | 1645 | default: |
| | 1646 | /* for anything else, we need only the event type code */ |
| | 1647 | ele_count = 1; |
| | 1648 | break; |
| | 1649 | } |
| | 1650 | |
| | 1651 | /* create the return list */ |
| | 1652 | lst_obj = CVmObjList::create(vmg_ FALSE, ele_count); |
| | 1653 | lst = (CVmObjList *)vm_objp(vmg_ lst_obj); |
| | 1654 | |
| | 1655 | /* save the list on the stack to protect against garbage collection */ |
| | 1656 | val.set_obj(lst_obj); |
| | 1657 | G_stk->push(&val); |
| | 1658 | |
| | 1659 | /* fill in the first element with the event type code */ |
| | 1660 | val.set_int(evt); |
| | 1661 | lst->cons_set_element(0, &val); |
| | 1662 | |
| | 1663 | /* set additional elements, according to the event type */ |
| | 1664 | switch(evt) |
| | 1665 | { |
| | 1666 | case OS_EVT_LINE: |
| | 1667 | case OS_EVT_TIMEOUT: |
| | 1668 | /* the second element is the line of text we read */ |
| | 1669 | val.set_obj(CVmObjString::create(vmg_ FALSE, buf, strlen(buf))); |
| | 1670 | lst->cons_set_element(1, &val); |
| | 1671 | break; |
| | 1672 | |
| | 1673 | default: |
| | 1674 | /* other event types have no extra data */ |
| | 1675 | break; |
| | 1676 | } |
| | 1677 | |
| | 1678 | /* return the list */ |
| | 1679 | retval_obj(vmg_ lst_obj); |
| | 1680 | |
| | 1681 | /* we can drop the garbage collection protection now */ |
| | 1682 | G_stk->discard(); |
| | 1683 | } |
| | 1684 | |
| | 1685 | /* ------------------------------------------------------------------------ */ |
| | 1686 | /* |
| | 1687 | * input_cancel - cancel input previously interrupted by timeout |
| | 1688 | */ |
| | 1689 | void CVmBifTIO::input_cancel(VMG_ uint argc) |
| | 1690 | { |
| | 1691 | vm_val_t val; |
| | 1692 | int reset; |
| | 1693 | |
| | 1694 | /* check arguments */ |
| | 1695 | check_argc(vmg_ argc, 1); |
| | 1696 | |
| | 1697 | /* get the 'reset' flag */ |
| | 1698 | G_stk->pop(&val); |
| | 1699 | reset = (val.typ == VM_TRUE); |
| | 1700 | |
| | 1701 | /* cancel the line */ |
| | 1702 | G_console->read_line_cancel(vmg_ reset); |
| | 1703 | } |
| | 1704 | |
| | 1705 | /* ------------------------------------------------------------------------ */ |
| | 1706 | /* |
| | 1707 | * Banner Window Functions |
| | 1708 | */ |
| | 1709 | |
| | 1710 | /* |
| | 1711 | * create a banner |
| | 1712 | */ |
| | 1713 | void CVmBifTIO::banner_create(VMG_ uint argc) |
| | 1714 | { |
| | 1715 | int parent_id; |
| | 1716 | int other_id; |
| | 1717 | int where; |
| | 1718 | int wintype; |
| | 1719 | int align; |
| | 1720 | int siz; |
| | 1721 | int siz_units; |
| | 1722 | unsigned long style; |
| | 1723 | int hdl; |
| | 1724 | |
| | 1725 | /* check arguments */ |
| | 1726 | check_argc_range(vmg_ argc, 7, 8); |
| | 1727 | |
| | 1728 | /* retrieve the 'parent' parameter */ |
| | 1729 | if (argc == 7) |
| | 1730 | { |
| | 1731 | /* |
| | 1732 | * there's no parent argument - this is an obsolete format for the |
| | 1733 | * arguments, but accept it for now, and simply treat it as |
| | 1734 | * equivalent to a nil parent |
| | 1735 | */ |
| | 1736 | parent_id = 0; |
| | 1737 | } |
| | 1738 | else if (G_stk->get(0)->typ == VM_NIL) |
| | 1739 | { |
| | 1740 | /* parent is nil - use zero as the ID and discard the nil */ |
| | 1741 | parent_id = 0; |
| | 1742 | G_stk->discard(); |
| | 1743 | } |
| | 1744 | else |
| | 1745 | { |
| | 1746 | /* retrieve the parent ID */ |
| | 1747 | parent_id = pop_int_val(vmg0_); |
| | 1748 | } |
| | 1749 | |
| | 1750 | /* retrieve the 'where' parameter */ |
| | 1751 | where = pop_int_val(vmg0_); |
| | 1752 | |
| | 1753 | /* retrieve the 'other' parameter, if it's needed for the 'where' */ |
| | 1754 | switch(where) |
| | 1755 | { |
| | 1756 | case OS_BANNER_BEFORE: |
| | 1757 | case OS_BANNER_AFTER: |
| | 1758 | /* we need another banner ID for the relative insertion point */ |
| | 1759 | other_id = pop_int_val(vmg0_); |
| | 1760 | break; |
| | 1761 | |
| | 1762 | default: |
| | 1763 | /* we don't need 'other' for this insertion point */ |
| | 1764 | other_id = 0; |
| | 1765 | G_stk->discard(); |
| | 1766 | break; |
| | 1767 | } |
| | 1768 | |
| | 1769 | /* retrieve the window type argument */ |
| | 1770 | wintype = pop_int_val(vmg0_); |
| | 1771 | |
| | 1772 | /* retrieve the alignment argument */ |
| | 1773 | align = pop_int_val(vmg0_); |
| | 1774 | |
| | 1775 | /* retrieve the size (as a percentage of the full screen size) */ |
| | 1776 | if (G_stk->get(0)->typ == VM_NIL) |
| | 1777 | { |
| | 1778 | /* nil size - use zero for the size */ |
| | 1779 | siz = 0; |
| | 1780 | siz_units = OS_BANNER_SIZE_ABS; |
| | 1781 | |
| | 1782 | /* discard the size and size units */ |
| | 1783 | G_stk->discard(); |
| | 1784 | G_stk->discard(); |
| | 1785 | } |
| | 1786 | else |
| | 1787 | { |
| | 1788 | /* retrieve the size and size units as integer values */ |
| | 1789 | siz = pop_int_val(vmg0_); |
| | 1790 | siz_units = pop_int_val(vmg0_); |
| | 1791 | } |
| | 1792 | |
| | 1793 | /* retrieve the flags */ |
| | 1794 | style = pop_long_val(vmg0_); |
| | 1795 | |
| | 1796 | /* try creating the banner */ |
| | 1797 | hdl = G_console->get_banner_manager()->create_banner( |
| | 1798 | vmg_ parent_id, where, other_id, wintype, |
| | 1799 | align, siz, siz_units, style); |
| | 1800 | |
| | 1801 | /* |
| | 1802 | * If we succeeded, return the handle; otherwise, return nil. A banner |
| | 1803 | * handle of zero indicates failure. |
| | 1804 | */ |
| | 1805 | if (hdl != 0) |
| | 1806 | retval_int(vmg_ hdl); |
| | 1807 | else |
| | 1808 | retval_nil(vmg0_); |
| | 1809 | } |
| | 1810 | |
| | 1811 | /* |
| | 1812 | * delete a banner |
| | 1813 | */ |
| | 1814 | void CVmBifTIO::banner_delete(VMG_ uint argc) |
| | 1815 | { |
| | 1816 | /* check arguments */ |
| | 1817 | check_argc(vmg_ argc, 1); |
| | 1818 | |
| | 1819 | /* delete the banner */ |
| | 1820 | G_console->get_banner_manager()->delete_banner(pop_int_val(vmg0_)); |
| | 1821 | } |
| | 1822 | |
| | 1823 | /* |
| | 1824 | * clear a window |
| | 1825 | */ |
| | 1826 | void CVmBifTIO::banner_clear(VMG_ uint argc) |
| | 1827 | { |
| | 1828 | int id; |
| | 1829 | CVmConsole *console; |
| | 1830 | |
| | 1831 | /* check arguments */ |
| | 1832 | check_argc(vmg_ argc, 1); |
| | 1833 | |
| | 1834 | /* get the banner ID */ |
| | 1835 | id = pop_int_val(vmg0_); |
| | 1836 | |
| | 1837 | /* get the banner - if it's invalid, throw an error */ |
| | 1838 | console = G_console->get_banner_manager()->get_console(id); |
| | 1839 | if (console == 0) |
| | 1840 | err_throw(VMERR_BAD_VAL_BIF); |
| | 1841 | |
| | 1842 | /* tell the console that we're clearing it */ |
| | 1843 | console->clear_window(vmg0_); |
| | 1844 | } |
| | 1845 | |
| | 1846 | /* |
| | 1847 | * write values to a banner |
| | 1848 | */ |
| | 1849 | void CVmBifTIO::banner_say(VMG_ uint argc) |
| | 1850 | { |
| | 1851 | CVmConsole *console; |
| | 1852 | |
| | 1853 | /* check arguments */ |
| | 1854 | check_argc_range(vmg_ argc, 1, 32767); |
| | 1855 | |
| | 1856 | /* get the banner - if it's invalid, throw an error */ |
| | 1857 | console = |
| | 1858 | G_console->get_banner_manager()->get_console(pop_int_val(vmg0_)); |
| | 1859 | if (console == 0) |
| | 1860 | err_throw(VMERR_BAD_VAL_BIF); |
| | 1861 | |
| | 1862 | /* |
| | 1863 | * write the argument(s) to the console (note that the first argument, |
| | 1864 | * which we've already retrieved, is the console handle, so don't count |
| | 1865 | * it among the arguments to display) |
| | 1866 | */ |
| | 1867 | say_to_console(vmg_ console, argc - 1); |
| | 1868 | } |
| | 1869 | |
| | 1870 | /* |
| | 1871 | * flush text to a banner |
| | 1872 | */ |
| | 1873 | void CVmBifTIO::banner_flush(VMG_ uint argc) |
| | 1874 | { |
| | 1875 | CVmConsole *console; |
| | 1876 | |
| | 1877 | /* check arguments */ |
| | 1878 | check_argc(vmg_ argc, 1); |
| | 1879 | |
| | 1880 | /* get the banner - if it's invalid, throw an error */ |
| | 1881 | console = |
| | 1882 | G_console->get_banner_manager()->get_console(pop_int_val(vmg0_)); |
| | 1883 | if (console == 0) |
| | 1884 | err_throw(VMERR_BAD_VAL_BIF); |
| | 1885 | |
| | 1886 | /* flush the console */ |
| | 1887 | console->flush(vmg_ VM_NL_NONE); |
| | 1888 | |
| | 1889 | /* immediately update the display */ |
| | 1890 | console->update_display(vmg0_); |
| | 1891 | } |
| | 1892 | |
| | 1893 | /* |
| | 1894 | * set the banner size |
| | 1895 | */ |
| | 1896 | void CVmBifTIO::banner_set_size(VMG_ uint argc) |
| | 1897 | { |
| | 1898 | int id; |
| | 1899 | void *hdl; |
| | 1900 | int siz; |
| | 1901 | int siz_units; |
| | 1902 | int is_advisory; |
| | 1903 | |
| | 1904 | /* check arguments */ |
| | 1905 | check_argc(vmg_ argc, 4); |
| | 1906 | |
| | 1907 | /* get the banner ID */ |
| | 1908 | id = pop_int_val(vmg0_); |
| | 1909 | |
| | 1910 | /* get the size and size units */ |
| | 1911 | siz = pop_int_val(vmg0_); |
| | 1912 | siz_units = pop_int_val(vmg0_); |
| | 1913 | |
| | 1914 | /* get the is-advisory flag */ |
| | 1915 | is_advisory = pop_bool_val(vmg0_); |
| | 1916 | |
| | 1917 | /* get the banner - if it's invalid, throw an error */ |
| | 1918 | hdl = G_console->get_banner_manager()->get_os_handle(id); |
| | 1919 | if (hdl == 0) |
| | 1920 | err_throw(VMERR_BAD_VAL_BIF); |
| | 1921 | |
| | 1922 | /* set the size */ |
| | 1923 | os_banner_set_size(hdl, siz, siz_units, is_advisory); |
| | 1924 | } |
| | 1925 | |
| | 1926 | /* |
| | 1927 | * size a banner to its contents in one or both dimensions |
| | 1928 | */ |
| | 1929 | void CVmBifTIO::banner_size_to_contents(VMG_ uint argc) |
| | 1930 | { |
| | 1931 | int id; |
| | 1932 | void *hdl; |
| | 1933 | CVmConsole *console; |
| | 1934 | |
| | 1935 | /* check arguments */ |
| | 1936 | check_argc(vmg_ argc, 1); |
| | 1937 | |
| | 1938 | /* get the banner ID */ |
| | 1939 | id = pop_int_val(vmg0_); |
| | 1940 | |
| | 1941 | /* get the banner - if it's invalid, throw an error */ |
| | 1942 | hdl = G_console->get_banner_manager()->get_os_handle(id); |
| | 1943 | console = G_console->get_banner_manager()->get_console(id); |
| | 1944 | if (hdl == 0 || console == 0) |
| | 1945 | err_throw(VMERR_BAD_VAL_BIF); |
| | 1946 | |
| | 1947 | /* make sure we've flushed any pending output to the banner */ |
| | 1948 | console->flush(vmg_ VM_NL_NONE); |
| | 1949 | |
| | 1950 | /* set the size */ |
| | 1951 | os_banner_size_to_contents(hdl); |
| | 1952 | } |
| | 1953 | |
| | 1954 | /* |
| | 1955 | * move the output position in a text grid banner |
| | 1956 | */ |
| | 1957 | void CVmBifTIO::banner_goto(VMG_ uint argc) |
| | 1958 | { |
| | 1959 | int id; |
| | 1960 | void *hdl; |
| | 1961 | CVmConsole *console; |
| | 1962 | int row, col; |
| | 1963 | |
| | 1964 | /* check arguments */ |
| | 1965 | check_argc(vmg_ argc, 3); |
| | 1966 | |
| | 1967 | /* get the banner ID */ |
| | 1968 | id = pop_int_val(vmg0_); |
| | 1969 | |
| | 1970 | /* get the coordinates */ |
| | 1971 | row = pop_int_val(vmg0_); |
| | 1972 | col = pop_int_val(vmg0_); |
| | 1973 | |
| | 1974 | /* make sure the values are valid */ |
| | 1975 | if (row < 1 || col < 1) |
| | 1976 | err_throw(VMERR_BAD_VAL_BIF); |
| | 1977 | |
| | 1978 | /* get the banner - if it's invalid, throw an error */ |
| | 1979 | hdl = G_console->get_banner_manager()->get_os_handle(id); |
| | 1980 | console = G_console->get_banner_manager()->get_console(id); |
| | 1981 | if (hdl == 0 || console == 0) |
| | 1982 | err_throw(VMERR_BAD_VAL_BIF); |
| | 1983 | |
| | 1984 | /* |
| | 1985 | * make sure we've flushed and discarded any pending output (since we |
| | 1986 | * don't want any pending output to show up at the new cursor position) |
| | 1987 | */ |
| | 1988 | console->flush(vmg_ VM_NL_NONE); |
| | 1989 | console->empty_buffers(vmg0_); |
| | 1990 | |
| | 1991 | /* move the cursor, adjusting from 1-based to 0-based coordinates */ |
| | 1992 | os_banner_goto(hdl, row - 1, col - 1); |
| | 1993 | } |
| | 1994 | |
| | 1995 | /* |
| | 1996 | * set the text color in a banner |
| | 1997 | */ |
| | 1998 | void CVmBifTIO::banner_set_text_color(VMG_ uint argc) |
| | 1999 | { |
| | 2000 | int id; |
| | 2001 | void *hdl; |
| | 2002 | CVmConsole *console; |
| | 2003 | os_color_t fg, bg; |
| | 2004 | |
| | 2005 | /* check arguments */ |
| | 2006 | check_argc(vmg_ argc, 3); |
| | 2007 | |
| | 2008 | /* get the banner ID */ |
| | 2009 | id = pop_int_val(vmg0_); |
| | 2010 | |
| | 2011 | /* get the foreground and background color values */ |
| | 2012 | fg = (os_color_t)pop_long_val(vmg0_); |
| | 2013 | bg = (os_color_t)pop_long_val(vmg0_); |
| | 2014 | |
| | 2015 | /* get the banner - if it's invalid, throw an error */ |
| | 2016 | hdl = G_console->get_banner_manager()->get_os_handle(id); |
| | 2017 | console = G_console->get_banner_manager()->get_console(id); |
| | 2018 | if (hdl == 0 || console == 0) |
| | 2019 | err_throw(VMERR_BAD_VAL_BIF); |
| | 2020 | |
| | 2021 | /* set the text output color in the console's formatter */ |
| | 2022 | console->set_text_color(vmg_ fg, bg); |
| | 2023 | } |
| | 2024 | |
| | 2025 | /* |
| | 2026 | * set the screen color in a banner |
| | 2027 | */ |
| | 2028 | void CVmBifTIO::banner_set_screen_color(VMG_ uint argc) |
| | 2029 | { |
| | 2030 | int id; |
| | 2031 | void *hdl; |
| | 2032 | CVmConsole *console; |
| | 2033 | os_color_t color; |
| | 2034 | |
| | 2035 | /* check arguments */ |
| | 2036 | check_argc(vmg_ argc, 2); |
| | 2037 | |
| | 2038 | /* get the banner ID */ |
| | 2039 | id = pop_int_val(vmg0_); |
| | 2040 | |
| | 2041 | /* get the body color */ |
| | 2042 | color = (os_color_t)pop_long_val(vmg0_); |
| | 2043 | |
| | 2044 | /* get the banner - if it's invalid, throw an error */ |
| | 2045 | hdl = G_console->get_banner_manager()->get_os_handle(id); |
| | 2046 | console = G_console->get_banner_manager()->get_console(id); |
| | 2047 | if (hdl == 0 || console == 0) |
| | 2048 | err_throw(VMERR_BAD_VAL_BIF); |
| | 2049 | |
| | 2050 | /* set the body color in the console */ |
| | 2051 | console->set_body_color(vmg_ color); |
| | 2052 | } |
| | 2053 | |
| | 2054 | /* service routine: store an integer in a list under construction */ |
| | 2055 | static void set_list_int(CVmObjList *lst, size_t idx, long intval) |
| | 2056 | { |
| | 2057 | vm_val_t val; |
| | 2058 | |
| | 2059 | /* set the value */ |
| | 2060 | val.set_int(intval); |
| | 2061 | |
| | 2062 | /* store it in the list */ |
| | 2063 | lst->cons_set_element(idx, &val); |
| | 2064 | } |
| | 2065 | |
| | 2066 | /* |
| | 2067 | * get information on a banner |
| | 2068 | */ |
| | 2069 | void CVmBifTIO::banner_get_info(VMG_ uint argc) |
| | 2070 | { |
| | 2071 | int id; |
| | 2072 | void *hdl; |
| | 2073 | os_banner_info_t info; |
| | 2074 | CVmConsoleBanner *console; |
| | 2075 | |
| | 2076 | /* check arguments */ |
| | 2077 | check_argc(vmg_ argc, 1); |
| | 2078 | |
| | 2079 | /* get the banner ID */ |
| | 2080 | id = pop_int_val(vmg0_); |
| | 2081 | |
| | 2082 | /* get the banner - if it's invalid, throw an error */ |
| | 2083 | hdl = G_console->get_banner_manager()->get_os_handle(id); |
| | 2084 | console = G_console->get_banner_manager()->get_console(id); |
| | 2085 | if (hdl == 0 || console == 0) |
| | 2086 | err_throw(VMERR_BAD_VAL_BIF); |
| | 2087 | |
| | 2088 | /* get information on the banner */ |
| | 2089 | if (console->get_banner_info(&info)) |
| | 2090 | { |
| | 2091 | vm_obj_id_t lst_obj; |
| | 2092 | CVmObjList *lst; |
| | 2093 | vm_val_t val; |
| | 2094 | |
| | 2095 | /* set up a return list with space for six entries */ |
| | 2096 | lst_obj = CVmObjList::create(vmg_ FALSE, 6); |
| | 2097 | lst = (CVmObjList *)vm_objp(vmg_ lst_obj); |
| | 2098 | |
| | 2099 | /* save the list on the stack to protect against garbage collection */ |
| | 2100 | val.set_obj(lst_obj); |
| | 2101 | G_stk->push(&val); |
| | 2102 | |
| | 2103 | /* |
| | 2104 | * return the values: [align, style, rows, columns, pix_height, |
| | 2105 | * pix_width] |
| | 2106 | */ |
| | 2107 | set_list_int(lst, 0, info.align); |
| | 2108 | set_list_int(lst, 1, info.style); |
| | 2109 | set_list_int(lst, 2, info.rows); |
| | 2110 | set_list_int(lst, 3, info.columns); |
| | 2111 | set_list_int(lst, 4, info.pix_height); |
| | 2112 | set_list_int(lst, 5, info.pix_width); |
| | 2113 | |
| | 2114 | /* return the list */ |
| | 2115 | retval_obj(vmg_ lst_obj); |
| | 2116 | |
| | 2117 | /* discard our gc protection */ |
| | 2118 | G_stk->discard(); |
| | 2119 | } |
| | 2120 | else |
| | 2121 | { |
| | 2122 | /* no information available - return nil */ |
| | 2123 | retval_nil(vmg0_); |
| | 2124 | } |
| | 2125 | } |
| | 2126 | |
| | 2127 | /* ------------------------------------------------------------------------ */ |
| | 2128 | /* |
| | 2129 | * Log Console Functions |
| | 2130 | */ |
| | 2131 | |
| | 2132 | /* |
| | 2133 | * create a log console |
| | 2134 | */ |
| | 2135 | void CVmBifTIO::log_console_create(VMG_ uint argc) |
| | 2136 | { |
| | 2137 | char fname[OSFNMAX]; |
| | 2138 | osfildef *fp; |
| | 2139 | CCharmapToLocal *cmap; |
| | 2140 | int width; |
| | 2141 | int hdl; |
| | 2142 | |
| | 2143 | /* check arguments */ |
| | 2144 | check_argc(vmg_ argc, 3); |
| | 2145 | |
| | 2146 | /* retrieve the log file name */ |
| | 2147 | pop_str_val_fname(vmg_ fname, sizeof(fname)); |
| | 2148 | |
| | 2149 | /* |
| | 2150 | * Retrieve the character mapper, which can be given as either a |
| | 2151 | * CharacterSet object or a string giving the character set name. |
| | 2152 | */ |
| | 2153 | if (G_stk->get(0)->typ == VM_NIL) |
| | 2154 | { |
| | 2155 | /* nil - use the default log file character set */ |
| | 2156 | cmap = G_cmap_to_log; |
| | 2157 | |
| | 2158 | /* add our reference to it */ |
| | 2159 | cmap->add_ref(); |
| | 2160 | } |
| | 2161 | else if (G_stk->get(0)->typ == VM_OBJ |
| | 2162 | && CVmObjCharSet::is_charset(vmg_ G_stk->get(0)->val.obj)) |
| | 2163 | { |
| | 2164 | vm_obj_id_t obj; |
| | 2165 | |
| | 2166 | /* it's a CharacterSet object - pop the reference */ |
| | 2167 | obj = CVmBif::pop_obj_val(vmg0_); |
| | 2168 | |
| | 2169 | /* retrieve the character mapper from the character set */ |
| | 2170 | cmap = ((CVmObjCharSet *)vm_objp(vmg_ obj))->get_to_local(vmg0_); |
| | 2171 | |
| | 2172 | /* add our reference to it */ |
| | 2173 | cmap->add_ref(); |
| | 2174 | } |
| | 2175 | else |
| | 2176 | { |
| | 2177 | const char *str; |
| | 2178 | size_t len; |
| | 2179 | char *nm; |
| | 2180 | |
| | 2181 | /* it's not a CharacterSet, so it must be a character set name */ |
| | 2182 | str = G_stk->get(0)->get_as_string(vmg0_); |
| | 2183 | if (str == 0) |
| | 2184 | err_throw(VMERR_BAD_TYPE_BIF); |
| | 2185 | |
| | 2186 | /* get the length and skip the length prefix */ |
| | 2187 | len = vmb_get_len(str); |
| | 2188 | str += VMB_LEN; |
| | 2189 | |
| | 2190 | /* get a null-terminated version of the name */ |
| | 2191 | nm = lib_copy_str(str, len); |
| | 2192 | |
| | 2193 | /* |
| | 2194 | * Create a character mapping for the given name. Note that this |
| | 2195 | * will automatically add a reference to the mapper on our behalf, |
| | 2196 | * so we don't have to add our own extra reference. |
| | 2197 | */ |
| | 2198 | cmap = CCharmapToLocal::load(G_host_ifc->get_cmap_res_loader(), nm); |
| | 2199 | |
| | 2200 | /* done with the null-terminated version of the name string */ |
| | 2201 | lib_free_str(nm); |
| | 2202 | |
| | 2203 | /* discard the argument */ |
| | 2204 | G_stk->discard(); |
| | 2205 | } |
| | 2206 | |
| | 2207 | /* if we didn't get a character map, use us-ascii by default */ |
| | 2208 | if (cmap == 0) |
| | 2209 | cmap = CCharmapToLocal::load(G_host_ifc->get_cmap_res_loader(), |
| | 2210 | "us-ascii"); |
| | 2211 | |
| | 2212 | err_try |
| | 2213 | { |
| | 2214 | /* make sure the file safety level allows the operation */ |
| | 2215 | CVmObjFile::check_safety_for_open(vmg_ fname, VMOBJFILE_ACCESS_WRITE); |
| | 2216 | |
| | 2217 | /* open the file for writing (in text mode) */ |
| | 2218 | fp = osfopwt(fname, OSFTLOG); |
| | 2219 | |
| | 2220 | /* if that failed, we can't contine */ |
| | 2221 | if (fp == 0) |
| | 2222 | G_interpreter->throw_new_class(vmg_ G_predef->file_creation_exc, |
| | 2223 | 0, "error creating log file"); |
| | 2224 | |
| | 2225 | /* retrieve the width */ |
| | 2226 | width = pop_int_val(vmg0_); |
| | 2227 | |
| | 2228 | /* create the log console */ |
| | 2229 | hdl = G_console->get_log_console_manager()->create_log_console( |
| | 2230 | fname, fp, cmap, width); |
| | 2231 | } |
| | 2232 | err_finally |
| | 2233 | { |
| | 2234 | /* |
| | 2235 | * release our character map reference - if we succeeded in |
| | 2236 | * creating the log console, it will have added its own reference |
| | 2237 | * by now |
| | 2238 | */ |
| | 2239 | cmap->release_ref(); |
| | 2240 | } |
| | 2241 | err_end; |
| | 2242 | |
| | 2243 | /* |
| | 2244 | * If we succeeded, return the handle; otherwise, return nil. A handle |
| | 2245 | * of zero indicates failure. |
| | 2246 | */ |
| | 2247 | if (hdl != 0) |
| | 2248 | retval_int(vmg_ hdl); |
| | 2249 | else |
| | 2250 | retval_nil(vmg0_); |
| | 2251 | } |
| | 2252 | |
| | 2253 | /* |
| | 2254 | * close (delete) a log console |
| | 2255 | */ |
| | 2256 | void CVmBifTIO::log_console_close(VMG_ uint argc) |
| | 2257 | { |
| | 2258 | int handle; |
| | 2259 | CVmConsole *console; |
| | 2260 | |
| | 2261 | /* check arguments */ |
| | 2262 | check_argc(vmg_ argc, 1); |
| | 2263 | |
| | 2264 | /* get the handle */ |
| | 2265 | handle = pop_int_val(vmg0_); |
| | 2266 | |
| | 2267 | /* get the console based on the handle */ |
| | 2268 | console = G_console->get_log_console_manager()->get_console(handle); |
| | 2269 | if (console == 0) |
| | 2270 | err_throw(VMERR_BAD_VAL_BIF); |
| | 2271 | |
| | 2272 | /* flush the console */ |
| | 2273 | console->flush(vmg_ VM_NL_NONE); |
| | 2274 | |
| | 2275 | /* delete the console */ |
| | 2276 | G_console->get_log_console_manager()->delete_log_console(handle); |
| | 2277 | } |
| | 2278 | |
| | 2279 | /* |
| | 2280 | * write values to a log console |
| | 2281 | */ |
| | 2282 | void CVmBifTIO::log_console_say(VMG_ uint argc) |
| | 2283 | { |
| | 2284 | int hdl; |
| | 2285 | CVmConsole *console; |
| | 2286 | CVmConsoleMainLog main_log_console; |
| | 2287 | |
| | 2288 | /* check arguments */ |
| | 2289 | check_argc_range(vmg_ argc, 1, 32767); |
| | 2290 | |
| | 2291 | /* get the console handle */ |
| | 2292 | hdl = pop_int_val(vmg0_); |
| | 2293 | |
| | 2294 | /* |
| | 2295 | * if it's the special value -1, it means that we want to write to the |
| | 2296 | * main console's log file; otherwise, it's a log console that we |
| | 2297 | * previously created explicitly via log_console_create() |
| | 2298 | */ |
| | 2299 | if (hdl == -1) |
| | 2300 | { |
| | 2301 | /* use the main log */ |
| | 2302 | console = &main_log_console; |
| | 2303 | } |
| | 2304 | else |
| | 2305 | { |
| | 2306 | /* get the console by handle - if it's invalid, throw an error */ |
| | 2307 | console = G_console->get_log_console_manager()->get_console(hdl); |
| | 2308 | if (console == 0) |
| | 2309 | err_throw(VMERR_BAD_VAL_BIF); |
| | 2310 | } |
| | 2311 | |
| | 2312 | /* |
| | 2313 | * write the argument(s) to the console (note that the first argument, |
| | 2314 | * which we've already retrieved, is the console handle, so don't count |
| | 2315 | * it among the arguments to display) |
| | 2316 | */ |
| | 2317 | say_to_console(vmg_ console, argc - 1); |
| | 2318 | } |
| | 2319 | |