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[] = "@(#)tcl.c 8.16 (Berkeley) 10/16/96";
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_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 \
47 scr_msg = __global_list->scr_msg; \
48 __global_list->scr_msg = msghandler;
49 #define ENDMESSAGE \
50 __global_list->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
tcl_fscreen(clientData,interp,argc,argv)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(Tcl_GetStringResult(interp), "%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
tcl_aline(clientData,interp,argc,argv)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;
108 rval = api_aline(sp, (recno_t)lno, argv[3], strlen(argv[3]));
109 ENDMESSAGE;
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
tcl_dline(clientData,interp,argc,argv)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;
142 rval = api_dline(sp, (recno_t)lno);
143 ENDMESSAGE;
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
tcl_gline(clientData,interp,argc,argv)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;
177 rval = api_gline(sp, (recno_t)lno, &p, &len);
178 ENDMESSAGE;
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
tcl_iline(clientData,interp,argc,argv)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;
219 rval = api_iline(sp, (recno_t)lno, argv[3], strlen(argv[3]));
220 ENDMESSAGE;
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
tcl_lline(clientData,interp,argc,argv)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 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;
252 rval = api_lline(sp, &last);
253 ENDMESSAGE;
254 if (rval)
255 return (TCL_ERROR);
256
257 (void)sprintf(Tcl_GetStringResult(interp), "%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
tcl_sline(clientData,interp,argc,argv)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;
289 rval = api_sline(sp, (recno_t)lno, argv[3], strlen(argv[3]));
290 ENDMESSAGE;
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
tcl_getmark(clientData,interp,argc,argv)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;
325 rval = api_getmark(sp, (int)argv[2][0], &cursor);
326 ENDMESSAGE;
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
tcl_setmark(clientData,interp,argc,argv)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;
372 rval = api_setmark(sp, (int)argv[2][0], &cursor);
373 ENDMESSAGE;
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
tcl_getcursor(clientData,interp,argc,argv)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;
408 rval = api_getcursor(sp, &cursor);
409 ENDMESSAGE;
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
tcl_setcursor(clientData,interp,argc,argv)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;
455 rval = api_setcursor(sp, &cursor);
456 ENDMESSAGE;
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
tcl_msg(clientData,interp,argc,argv)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
tcl_iscreen(clientData,interp,argc,argv)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;
517 rval = api_edit(sp, argv[2], &nsp, 1);
518 ENDMESSAGE;
519
520 if (rval)
521 return (TCL_ERROR);
522
523 (void)sprintf(Tcl_GetStringResult(interp), "%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
tcl_escreen(clientData,interp,argc,argv)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;
554 rval = api_escreen(sp);
555 ENDMESSAGE;
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
tcl_swscreen(clientData,interp,argc,argv)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;
590 rval = api_swscreen(sp, new);
591 ENDMESSAGE;
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
tcl_map(clientData,interp,argc,argv)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;
624 (void)snprintf(command, sizeof(command), ":tcl %s\n", argv[3]);
625 rval = api_map(sp, argv[2], command, strlen(command));
626 ENDMESSAGE;
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
tcl_unmap(clientData,interp,argc,argv)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;
658 rval = api_unmap(sp, argv[2]);
659 ENDMESSAGE;
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
tcl_opts_set(clientData,interp,argc,argv)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;
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;
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
tcl_opts_get(clientData,interp,argc,argv)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;
731 rval = api_opts_get(sp, argv[2], &value, NULL);
732 ENDMESSAGE;
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
tcl_init(gp)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
getscreenid(interp,spp,id,name)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 recno_t and size_t are larger than ints.
816 */
817 static int
getint(interp,msg,s,intp)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
msghandler(sp,mtype,msg,len)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