1 /*- 2 * Copyright (c) 1992, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1992, 1993, 1994, 1995 5 * Keith Bostic. All rights reserved. 6 * Copyright (c) 1995 7 * George V. Neville-Neil. All rights reserved. 8 * 9 * See the LICENSE file for redistribution information. 10 */ 11 12 #include "config.h" 13 14 #ifndef lint 15 static const char sccsid[] = "Id: tcl.c,v 8.19 2001/08/24 12:17:27 skimo Exp (Berkeley) Date: 2001/08/24 12:17:27 "; 16 #endif /* not lint */ 17 18 #include <sys/types.h> 19 #include <sys/queue.h> 20 #include <sys/time.h> 21 22 #include <bitstring.h> 23 #include <errno.h> 24 #include <limits.h> 25 #include <signal.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <tcl.h> 30 #include <termios.h> 31 #include <unistd.h> 32 33 #include "../common/common.h" 34 #include "tcl_api_extern.h" 35 36 static int getint __P((Tcl_Interp *, char *, char *, int *)); 37 static int getscreenid __P((Tcl_Interp *, SCR **, char *, char *)); 38 static void msghandler __P((SCR *, mtype_t, char *, size_t)); 39 40 extern GS *__global_list; /* XXX */ 41 42 /* 43 * INITMESSAGE -- 44 * Macros to point messages at the Tcl message handler. 45 */ 46 #define INITMESSAGE(sp) \ 47 scr_msg = sp->wp->scr_msg; \ 48 sp->wp->scr_msg = msghandler; 49 #define ENDMESSAGE(sp) \ 50 sp->wp->scr_msg = scr_msg; 51 52 /* 53 * tcl_fscreen -- 54 * Return the screen id associated with file name. 55 * 56 * Tcl Command: viFindScreen 57 * Usage: viFindScreen file 58 */ 59 static int 60 tcl_fscreen(clientData, interp, argc, argv) 61 ClientData clientData; 62 Tcl_Interp *interp; 63 int argc; 64 char **argv; 65 { 66 SCR *sp; 67 68 if (argc != 2) { 69 Tcl_SetResult(interp, "Usage: viFindScreen file", TCL_STATIC); 70 return (TCL_ERROR); 71 } 72 73 if (getscreenid(interp, &sp, NULL, argv[1])) 74 return (TCL_ERROR); 75 76 (void)sprintf(interp->result, "%d", sp->id); 77 return (TCL_OK); 78 } 79 80 /* 81 * tcl_aline -- 82 * -- Append the string text after the line in lineNumber. 83 * 84 * Tcl Command: viAppendLine 85 * Usage: viAppendLine screenId lineNumber text 86 */ 87 static int 88 tcl_aline(clientData, interp, argc, argv) 89 ClientData clientData; 90 Tcl_Interp *interp; 91 int argc; 92 char **argv; 93 { 94 SCR *sp; 95 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 96 int lno, rval; 97 98 if (argc != 4) { 99 Tcl_SetResult(interp, 100 "Usage: viAppendLine screenId lineNumber text", TCL_STATIC); 101 return (TCL_ERROR); 102 } 103 104 if (getscreenid(interp, &sp, argv[1], NULL) || 105 getint(interp, "line number", argv[2], &lno)) 106 return (TCL_ERROR); 107 INITMESSAGE(sp); 108 rval = api_aline(sp, (db_recno_t)lno, argv[3], strlen(argv[3])); 109 ENDMESSAGE(sp); 110 111 return (rval ? TCL_ERROR : TCL_OK); 112 } 113 114 /* 115 * tcl_dline -- 116 * Delete lineNum. 117 * 118 * Tcl Command: viDelLine 119 * Usage: viDelLine screenId lineNum 120 */ 121 static int 122 tcl_dline(clientData, interp, argc, argv) 123 ClientData clientData; 124 Tcl_Interp *interp; 125 int argc; 126 char **argv; 127 { 128 SCR *sp; 129 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 130 int lno, rval; 131 132 if (argc != 3) { 133 Tcl_SetResult(interp, 134 "Usage: viDelLine screenId lineNumber", TCL_STATIC); 135 return (TCL_ERROR); 136 } 137 138 if (getscreenid(interp, &sp, argv[1], NULL) || 139 getint(interp, "line number", argv[2], &lno)) 140 return (TCL_ERROR); 141 INITMESSAGE(sp); 142 rval = api_dline(sp, (db_recno_t)lno); 143 ENDMESSAGE(sp); 144 145 return (rval ? TCL_ERROR : TCL_OK); 146 } 147 148 /* 149 * tcl_gline -- 150 * Return lineNumber. 151 * 152 * Tcl Command: viGetLine 153 * Usage: viGetLine screenId lineNumber 154 */ 155 static int 156 tcl_gline(clientData, interp, argc, argv) 157 ClientData clientData; 158 Tcl_Interp *interp; 159 int argc; 160 char **argv; 161 { 162 SCR *sp; 163 size_t len; 164 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 165 int lno, rval; 166 char *line, *p; 167 168 if (argc != 3) { 169 Tcl_SetResult(interp, 170 "Usage: viGetLine screenId lineNumber", TCL_STATIC); 171 return (TCL_ERROR); 172 } 173 if (getscreenid(interp, &sp, argv[1], NULL) || 174 getint(interp, "line number", argv[2], &lno)) 175 return (TCL_ERROR); 176 INITMESSAGE(sp); 177 rval = api_gline(sp, (db_recno_t)lno, &p, &len); 178 ENDMESSAGE(sp); 179 180 if (rval) 181 return (TCL_ERROR); 182 183 if ((line = malloc(len + 1)) == NULL) 184 exit(1); /* XXX */ 185 memmove(line, p, len); 186 line[len] = '\0'; 187 Tcl_SetResult(interp, line, TCL_DYNAMIC); 188 return (TCL_OK); 189 } 190 191 /* 192 * tcl_iline -- 193 * Insert the string text after the line in lineNumber. 194 * 195 * Tcl Command: viInsertLine 196 * Usage: viInsertLine screenId lineNumber text 197 */ 198 static int 199 tcl_iline(clientData, interp, argc, argv) 200 ClientData clientData; 201 Tcl_Interp *interp; 202 int argc; 203 char **argv; 204 { 205 SCR *sp; 206 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 207 int lno, rval; 208 209 if (argc != 4) { 210 Tcl_SetResult(interp, 211 "Usage: viInsertLine screenId lineNumber text", TCL_STATIC); 212 return (TCL_ERROR); 213 } 214 215 if (getscreenid(interp, &sp, argv[1], NULL) || 216 getint(interp, "line number", argv[2], &lno)) 217 return (TCL_ERROR); 218 INITMESSAGE(sp); 219 rval = api_iline(sp, (db_recno_t)lno, argv[3], strlen(argv[3])); 220 ENDMESSAGE(sp); 221 222 return (rval ? TCL_ERROR : TCL_OK); 223 } 224 225 /* 226 * tcl_lline -- 227 * Return the last line in the screen. 228 * 229 * Tcl Command: viLastLine 230 * Usage: viLastLine screenId 231 */ 232 static int 233 tcl_lline(clientData, interp, argc, argv) 234 ClientData clientData; 235 Tcl_Interp *interp; 236 int argc; 237 char **argv; 238 { 239 SCR *sp; 240 db_recno_t last; 241 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 242 int rval; 243 244 if (argc != 2) { 245 Tcl_SetResult(interp, "Usage: viLastLine screenId", TCL_STATIC); 246 return (TCL_ERROR); 247 } 248 249 if (getscreenid(interp, &sp, argv[1], NULL)) 250 return (TCL_ERROR); 251 INITMESSAGE(sp); 252 rval = api_lline(sp, &last); 253 ENDMESSAGE(sp); 254 if (rval) 255 return (TCL_ERROR); 256 257 (void)sprintf(interp->result, "%lu", (unsigned long)last); 258 return (TCL_OK); 259 } 260 261 /* 262 * tcl_sline -- 263 * Set lineNumber to the text supplied. 264 * 265 * Tcl Command: viSetLine 266 * Usage: viSetLine screenId lineNumber text 267 */ 268 static int 269 tcl_sline(clientData, interp, argc, argv) 270 ClientData clientData; 271 Tcl_Interp *interp; 272 int argc; 273 char **argv; 274 { 275 SCR *sp; 276 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 277 int lno, rval; 278 279 if (argc != 4) { 280 Tcl_SetResult(interp, 281 "Usage: viSetLine screenId lineNumber text", TCL_STATIC); 282 return (TCL_ERROR); 283 } 284 285 if (getscreenid(interp, &sp, argv[1], NULL) || 286 getint(interp, "line number", argv[2], &lno)) 287 return (TCL_ERROR); 288 INITMESSAGE(sp); 289 rval = api_sline(sp, (db_recno_t)lno, argv[3], strlen(argv[3])); 290 ENDMESSAGE(sp); 291 292 return (rval ? TCL_ERROR : TCL_OK); 293 } 294 295 /* 296 * tcl_getmark -- 297 * Return the mark's cursor position as a list with two elements. 298 * {line, column}. 299 * 300 * Tcl Command: viGetMark 301 * Usage: viGetMark screenId mark 302 */ 303 static int 304 tcl_getmark(clientData, interp, argc, argv) 305 ClientData clientData; 306 Tcl_Interp *interp; 307 int argc; 308 char **argv; 309 { 310 MARK cursor; 311 SCR *sp; 312 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 313 int rval; 314 char buf[20]; 315 316 if (argc != 3) { 317 Tcl_SetResult(interp, 318 "Usage: viGetMark screenId mark", TCL_STATIC); 319 return (TCL_ERROR); 320 } 321 322 if (getscreenid(interp, &sp, argv[1], NULL)) 323 return (TCL_ERROR); 324 INITMESSAGE(sp); 325 rval = api_getmark(sp, (int)argv[2][0], &cursor); 326 ENDMESSAGE(sp); 327 328 if (rval) 329 return (TCL_ERROR); 330 331 (void)snprintf(buf, sizeof(buf), "%lu", (u_long)cursor.lno); 332 Tcl_AppendElement(interp, buf); 333 (void)snprintf(buf, sizeof(buf), "%lu", (u_long)cursor.cno); 334 Tcl_AppendElement(interp, buf); 335 return (TCL_OK); 336 } 337 338 /* 339 * tcl_setmark -- 340 * Set the mark to the line and column numbers supplied. 341 * 342 * Tcl Command: viSetMark 343 * Usage: viSetMark screenId mark line column 344 */ 345 static int 346 tcl_setmark(clientData, interp, argc, argv) 347 ClientData clientData; 348 Tcl_Interp *interp; 349 int argc; 350 char **argv; 351 { 352 MARK cursor; 353 SCR *sp; 354 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 355 int i, rval; 356 357 if (argc != 5) { 358 Tcl_SetResult(interp, 359 "Usage: viSetMark screenId mark line column", TCL_STATIC); 360 return (TCL_ERROR); 361 } 362 363 if (getscreenid(interp, &sp, argv[1], NULL)) 364 return (TCL_ERROR); 365 if (getint(interp, "line number", argv[3], &i)) 366 return (TCL_ERROR); 367 cursor.lno = i; 368 if (getint(interp, "column number", argv[4], &i)) 369 return (TCL_ERROR); 370 cursor.cno = i; 371 INITMESSAGE(sp); 372 rval = api_setmark(sp, (int)argv[2][0], &cursor); 373 ENDMESSAGE(sp); 374 375 return (rval ? TCL_ERROR : TCL_OK); 376 } 377 378 /* 379 * tcl_getcursor -- 380 * Return the current cursor position as a list with two elements. 381 * {line, column}. 382 * 383 * Tcl Command: viGetCursor 384 * Usage: viGetCursor screenId 385 */ 386 static int 387 tcl_getcursor(clientData, interp, argc, argv) 388 ClientData clientData; 389 Tcl_Interp *interp; 390 int argc; 391 char **argv; 392 { 393 MARK cursor; 394 SCR *sp; 395 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 396 int rval; 397 char buf[20]; 398 399 if (argc != 2) { 400 Tcl_SetResult(interp, 401 "Usage: viGetCursor screenId", TCL_STATIC); 402 return (TCL_ERROR); 403 } 404 405 if (getscreenid(interp, &sp, argv[1], NULL)) 406 return (TCL_ERROR); 407 INITMESSAGE(sp); 408 rval = api_getcursor(sp, &cursor); 409 ENDMESSAGE(sp); 410 411 if (rval) 412 return (TCL_ERROR); 413 414 (void)snprintf(buf, sizeof(buf), "%lu", (u_long)cursor.lno); 415 Tcl_AppendElement(interp, buf); 416 (void)snprintf(buf, sizeof(buf), "%lu", (u_long)cursor.cno); 417 Tcl_AppendElement(interp, buf); 418 return (TCL_OK); 419 } 420 421 /* 422 * tcl_setcursor -- 423 * Set the cursor to the line and column numbers supplied. 424 * 425 * Tcl Command: viSetCursor 426 * Usage: viSetCursor screenId line column 427 */ 428 static int 429 tcl_setcursor(clientData, interp, argc, argv) 430 ClientData clientData; 431 Tcl_Interp *interp; 432 int argc; 433 char **argv; 434 { 435 MARK cursor; 436 SCR *sp; 437 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 438 int i, rval; 439 440 if (argc != 4) { 441 Tcl_SetResult(interp, 442 "Usage: viSetCursor screenId line column", TCL_STATIC); 443 return (TCL_ERROR); 444 } 445 446 if (getscreenid(interp, &sp, argv[1], NULL)) 447 return (TCL_ERROR); 448 if (getint(interp, "screen id", argv[2], &i)) 449 return (TCL_ERROR); 450 cursor.lno = i; 451 if (getint(interp, "screen id", argv[3], &i)) 452 return (TCL_ERROR); 453 cursor.cno = i; 454 INITMESSAGE(sp); 455 rval = api_setcursor(sp, &cursor); 456 ENDMESSAGE(sp); 457 458 return (rval ? TCL_ERROR : TCL_OK); 459 } 460 461 /* 462 * tcl_msg -- 463 * Set the message line to text. 464 * 465 * Tcl Command: viMsg 466 * Usage: viMsg screenId text 467 */ 468 static int 469 tcl_msg(clientData, interp, argc, argv) 470 ClientData clientData; 471 Tcl_Interp *interp; 472 int argc; 473 char **argv; 474 { 475 SCR *sp; 476 477 if (argc != 3) { 478 Tcl_SetResult(interp, "Usage: viMsg screenId text", TCL_STATIC); 479 return (TCL_ERROR); 480 } 481 482 if (getscreenid(interp, &sp, argv[1], NULL)) 483 return (TCL_ERROR); 484 api_imessage(sp, argv[2]); 485 486 return (TCL_OK); 487 } 488 489 /* 490 * tcl_iscreen -- 491 * Create a new screen. If a filename is specified then the screen 492 * is opened with that file. 493 * 494 * Tcl Command: viNewScreen 495 * Usage: viNewScreen screenId [file] 496 */ 497 static int 498 tcl_iscreen(clientData, interp, argc, argv) 499 ClientData clientData; 500 Tcl_Interp *interp; 501 int argc; 502 char **argv; 503 { 504 SCR *sp, *nsp; 505 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 506 int rval; 507 508 if (argc != 2 && argc != 3) { 509 Tcl_SetResult(interp, 510 "Usage: viNewScreen screenId [file]", TCL_STATIC); 511 return (TCL_ERROR); 512 } 513 514 if (getscreenid(interp, &sp, argv[1], NULL)) 515 return (TCL_ERROR); 516 INITMESSAGE(sp); 517 rval = api_edit(sp, argv[2], &nsp, 1); 518 ENDMESSAGE(sp); 519 520 if (rval) 521 return (TCL_ERROR); 522 523 (void)sprintf(interp->result, "%d", nsp->id); 524 return (TCL_OK); 525 } 526 527 /* 528 * tcl_escreen -- 529 * End a screen. 530 * 531 * Tcl Command: viEndScreen 532 * Usage: viEndScreen screenId 533 */ 534 static int 535 tcl_escreen(clientData, interp, argc, argv) 536 ClientData clientData; 537 Tcl_Interp *interp; 538 int argc; 539 char **argv; 540 { 541 SCR *sp; 542 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 543 int rval; 544 545 if (argc != 2) { 546 Tcl_SetResult(interp, 547 "Usage: viEndScreen screenId", TCL_STATIC); 548 return (TCL_ERROR); 549 } 550 551 if (getscreenid(interp, &sp, argv[1], NULL)) 552 return (TCL_ERROR); 553 INITMESSAGE(sp); 554 rval = api_escreen(sp); 555 ENDMESSAGE(sp); 556 557 return (rval ? TCL_ERROR : TCL_OK); 558 } 559 560 /* 561 * tcl_swscreen -- 562 * Change the current focus to screen. 563 * 564 * Tcl Command: viSwitchScreen 565 * Usage: viSwitchScreen screenId screenId 566 */ 567 static int 568 tcl_swscreen(clientData, interp, argc, argv) 569 ClientData clientData; 570 Tcl_Interp *interp; 571 int argc; 572 char **argv; 573 { 574 SCR *sp, *new; 575 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 576 int rval; 577 578 if (argc != 3) { 579 Tcl_SetResult(interp, 580 "Usage: viSwitchScreen cur_screenId new_screenId", 581 TCL_STATIC); 582 return (TCL_ERROR); 583 } 584 585 if (getscreenid(interp, &sp, argv[1], NULL)) 586 return (TCL_ERROR); 587 if (getscreenid(interp, &new, argv[2], NULL)) 588 return (TCL_ERROR); 589 INITMESSAGE(sp); 590 rval = api_swscreen(sp, new); 591 ENDMESSAGE(sp); 592 593 return (rval ? TCL_ERROR : TCL_OK); 594 } 595 596 /* 597 * tcl_map -- 598 * Associate a key with a tcl procedure. 599 * 600 * Tcl Command: viMapKey 601 * Usage: viMapKey screenId key tclproc 602 */ 603 static int 604 tcl_map(clientData, interp, argc, argv) 605 ClientData clientData; 606 Tcl_Interp *interp; 607 int argc; 608 char **argv; 609 { 610 SCR *sp; 611 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 612 int rval; 613 char command[256]; 614 615 if (argc != 4) { 616 Tcl_SetResult(interp, 617 "Usage: viMapKey screenId key tclproc", TCL_STATIC); 618 return (TCL_ERROR); 619 } 620 621 if (getscreenid(interp, &sp, argv[1], NULL)) 622 return (TCL_ERROR); 623 INITMESSAGE(sp); 624 (void)snprintf(command, sizeof(command), ":tcl %s\n", argv[3]); 625 rval = api_map(sp, argv[2], command, strlen(command)); 626 ENDMESSAGE(sp); 627 628 return (rval ? TCL_ERROR : TCL_OK); 629 } 630 631 /* 632 * tcl_unmap -- 633 * Unmap a key. 634 * 635 * Tcl Command: viUnmapKey 636 * Usage: viUnmMapKey screenId key 637 */ 638 static int 639 tcl_unmap(clientData, interp, argc, argv) 640 ClientData clientData; 641 Tcl_Interp *interp; 642 int argc; 643 char **argv; 644 { 645 SCR *sp; 646 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 647 int rval; 648 649 if (argc != 3) { 650 Tcl_SetResult(interp, 651 "Usage: viUnmapKey screenId key", TCL_STATIC); 652 return (TCL_ERROR); 653 } 654 655 if (getscreenid(interp, &sp, argv[1], NULL)) 656 return (TCL_ERROR); 657 INITMESSAGE(sp); 658 rval = api_unmap(sp, argv[2]); 659 ENDMESSAGE(sp); 660 661 return (rval ? TCL_ERROR : TCL_OK); 662 } 663 664 /* 665 * tcl_opts_set -- 666 * Set an option. 667 * 668 * Tcl Command: viSetOpt 669 * Usage: viSetOpt screenId command 670 */ 671 static int 672 tcl_opts_set(clientData, interp, argc, argv) 673 ClientData clientData; 674 Tcl_Interp *interp; 675 int argc; 676 char **argv; 677 { 678 SCR *sp; 679 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 680 int rval; 681 char *setting; 682 683 if (argc != 3) { 684 Tcl_SetResult(interp, 685 "Usage: viSetOpt screenId command", TCL_STATIC); 686 return (TCL_ERROR); 687 } 688 689 if (getscreenid(interp, &sp, argv[1], NULL)) 690 return (TCL_ERROR); 691 INITMESSAGE(sp); 692 /*rval = api_opts_set(sp, argv[2]);*/ 693 MALLOC(sp, setting, char *, strlen(argv[2])+6); 694 strcpy(setting, ":set "); 695 strcpy(setting+5, argv[2]); 696 rval=api_run_str(sp, setting); 697 free(setting); 698 ENDMESSAGE(sp); 699 700 return (rval ? TCL_ERROR : TCL_OK); 701 } 702 703 /* 704 * tcl_opts_get -- 705 Return the value of an option. 706 * 707 * Tcl Command: viGetOpt 708 * Usage: viGetOpt screenId option 709 */ 710 static int 711 tcl_opts_get(clientData, interp, argc, argv) 712 ClientData clientData; 713 Tcl_Interp *interp; 714 int argc; 715 char **argv; 716 { 717 SCR *sp; 718 void (*scr_msg) __P((SCR *, mtype_t, char *, size_t)); 719 int rval; 720 char *value; 721 722 if (argc != 3) { 723 Tcl_SetResult(interp, 724 "Usage: viGetOpt screenId option", TCL_STATIC); 725 return (TCL_ERROR); 726 } 727 728 if (getscreenid(interp, &sp, argv[1], NULL)) 729 return (TCL_ERROR); 730 INITMESSAGE(sp); 731 rval = api_opts_get(sp, argv[2], &value, NULL); 732 ENDMESSAGE(sp); 733 if (rval) 734 return (TCL_ERROR); 735 736 Tcl_SetResult(interp, value, TCL_DYNAMIC); 737 return (TCL_OK); 738 } 739 740 /* 741 * tcl_init -- 742 * Create the TCL commands used by nvi. 743 * 744 * PUBLIC: int tcl_init __P((GS *)); 745 */ 746 int 747 tcl_init(gp) 748 GS *gp; 749 { 750 gp->tcl_interp = Tcl_CreateInterp(); 751 if (Tcl_Init(gp->tcl_interp) == TCL_ERROR) 752 return (1); 753 754 #define TCC(name, function) { \ 755 Tcl_CreateCommand(gp->tcl_interp, name, function, \ 756 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); \ 757 } 758 TCC("viAppendLine", tcl_aline); 759 TCC("viDelLine", tcl_dline); 760 TCC("viEndScreen", tcl_escreen); 761 TCC("viFindScreen", tcl_fscreen); 762 TCC("viGetCursor", tcl_getcursor); 763 TCC("viGetLine", tcl_gline); 764 TCC("viGetMark", tcl_getmark); 765 TCC("viGetOpt", tcl_opts_get); 766 TCC("viInsertLine", tcl_iline); 767 TCC("viLastLine", tcl_lline); 768 TCC("viMapKey", tcl_map); 769 TCC("viMsg", tcl_msg); 770 TCC("viNewScreen", tcl_iscreen); 771 TCC("viSetCursor", tcl_setcursor); 772 TCC("viSetLine", tcl_sline); 773 TCC("viSetMark", tcl_setmark); 774 TCC("viSetOpt", tcl_opts_set); 775 TCC("viSwitchScreen", tcl_swscreen); 776 TCC("viUnmapKey", tcl_unmap); 777 778 return (0); 779 } 780 781 /* 782 * getscreenid -- 783 * Get the specified screen pointer. 784 * 785 * XXX 786 * This is fatal. We can't post a message into vi that we're unable to find 787 * the screen without first finding the screen... So, this must be the first 788 * thing a Tcl routine does, and, if it fails, the last as well. 789 */ 790 static int 791 getscreenid(interp, spp, id, name) 792 Tcl_Interp *interp; 793 SCR **spp; 794 char *id, *name; 795 { 796 int scr_no; 797 char buf[64]; 798 799 if (id != NULL && getint(interp, "screen id", id, &scr_no)) 800 return (1); 801 if ((*spp = api_fscreen(scr_no, name)) == NULL) { 802 (void)snprintf(buf, sizeof(buf), 803 "unknown screen id: %s", name == NULL ? id : name); 804 Tcl_SetResult(interp, buf, TCL_VOLATILE); 805 return (1); 806 } 807 return (0); 808 } 809 810 /* 811 * getint -- 812 * Get a Tcl integer. 813 * 814 * XXX 815 * This code assumes that both db_recno_t and size_t are larger than ints. 816 */ 817 static int 818 getint(interp, msg, s, intp) 819 Tcl_Interp *interp; 820 char *msg, *s; 821 int *intp; 822 { 823 char buf[64]; 824 825 if (Tcl_GetInt(interp, s, intp) == TCL_ERROR) 826 return (1); 827 if (*intp < 0) { 828 (void)snprintf(buf, sizeof(buf), 829 "illegal %s %s: may not be negative", msg, s); 830 Tcl_SetResult(interp, buf, TCL_VOLATILE); 831 return (1); 832 } 833 return (0); 834 } 835 836 /* 837 * msghandler -- 838 * Tcl message routine so that error messages are processed in 839 * Tcl, not in nvi. 840 */ 841 static void 842 msghandler(sp, mtype, msg, len) 843 SCR *sp; 844 mtype_t mtype; 845 char *msg; 846 size_t len; 847 { 848 /* Replace the trailing <newline> with an EOS. */ 849 msg[len - 1] = '\0'; 850 851 Tcl_SetResult(sp->gp->tcl_interp, msg, TCL_VOLATILE); 852 } 853