Merge from vendor branch GCC:
[dragonfly.git] / contrib / nvi / tcl_api / tcl.c
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
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;
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
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
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
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
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(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;
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
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
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
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
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
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;
517         rval = api_edit(sp, argv[2], &nsp, 1);
518         ENDMESSAGE;
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;
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
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
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
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
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
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
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 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 }