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