4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1992, 1993, 1994, 1995
7 * Keith Bostic. All rights reserved.
9 * George V. Neville-Neil. All rights reserved.
11 * See the LICENSE file for redistribution information.
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";
20 #include <sys/types.h>
21 #include <sys/queue.h>
24 #include <bitstring.h>
35 #include "../common/common.h"
38 static int getint
__P((Tcl_Interp
*, char *, char *, int *));
39 static int getscreenid
__P((Tcl_Interp
*, SCR
**, char *, char *));
40 static void msghandler
__P((SCR
*, mtype_t
, char *, size_t));
42 extern GS
*__global_list
; /* XXX */
46 * Macros to point messages at the Tcl message handler.
48 #define INITMESSAGE(sp) \
49 scr_msg = sp->wp->scr_msg; \
50 sp->wp->scr_msg = msghandler;
51 #define ENDMESSAGE(sp) \
52 sp->wp->scr_msg = scr_msg;
56 * Return the screen id associated with file name.
58 * Tcl Command: viFindScreen
59 * Usage: viFindScreen file
62 tcl_fscreen(clientData
, interp
, argc
, argv
)
63 ClientData clientData
;
71 Tcl_SetResult(interp
, "Usage: viFindScreen file", TCL_STATIC
);
75 if (getscreenid(interp
, &sp
, NULL
, argv
[1]))
78 (void)sprintf(interp
->result
, "%d", sp
->id
);
84 * -- Append the string text after the line in lineNumber.
86 * Tcl Command: viAppendLine
87 * Usage: viAppendLine screenId lineNumber text
90 tcl_aline(clientData
, interp
, argc
, argv
)
91 ClientData clientData
;
97 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
101 Tcl_SetResult(interp
,
102 "Usage: viAppendLine screenId lineNumber text", TCL_STATIC
);
106 if (getscreenid(interp
, &sp
, argv
[1], NULL
) ||
107 getint(interp
, "line number", argv
[2], &lno
))
110 rval
= api_aline(sp
, (db_recno_t
)lno
, argv
[3], strlen(argv
[3]));
113 return (rval
? TCL_ERROR
: TCL_OK
);
120 * Tcl Command: viDelLine
121 * Usage: viDelLine screenId lineNum
124 tcl_dline(clientData
, interp
, argc
, argv
)
125 ClientData clientData
;
131 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
135 Tcl_SetResult(interp
,
136 "Usage: viDelLine screenId lineNumber", TCL_STATIC
);
140 if (getscreenid(interp
, &sp
, argv
[1], NULL
) ||
141 getint(interp
, "line number", argv
[2], &lno
))
144 rval
= api_dline(sp
, (db_recno_t
)lno
);
147 return (rval
? TCL_ERROR
: TCL_OK
);
154 * Tcl Command: viGetLine
155 * Usage: viGetLine screenId lineNumber
158 tcl_gline(clientData
, interp
, argc
, argv
)
159 ClientData clientData
;
166 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
171 Tcl_SetResult(interp
,
172 "Usage: viGetLine screenId lineNumber", TCL_STATIC
);
175 if (getscreenid(interp
, &sp
, argv
[1], NULL
) ||
176 getint(interp
, "line number", argv
[2], &lno
))
179 rval
= api_gline(sp
, (db_recno_t
)lno
, &p
, &len
);
185 if ((line
= malloc(len
+ 1)) == NULL
)
187 memmove(line
, p
, len
);
189 Tcl_SetResult(interp
, line
, TCL_DYNAMIC
);
195 * Insert the string text after the line in lineNumber.
197 * Tcl Command: viInsertLine
198 * Usage: viInsertLine screenId lineNumber text
201 tcl_iline(clientData
, interp
, argc
, argv
)
202 ClientData clientData
;
208 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
212 Tcl_SetResult(interp
,
213 "Usage: viInsertLine screenId lineNumber text", TCL_STATIC
);
217 if (getscreenid(interp
, &sp
, argv
[1], NULL
) ||
218 getint(interp
, "line number", argv
[2], &lno
))
221 rval
= api_iline(sp
, (db_recno_t
)lno
, argv
[3], strlen(argv
[3]));
224 return (rval
? TCL_ERROR
: TCL_OK
);
229 * Return the last line in the screen.
231 * Tcl Command: viLastLine
232 * Usage: viLastLine screenId
235 tcl_lline(clientData
, interp
, argc
, argv
)
236 ClientData clientData
;
243 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
247 Tcl_SetResult(interp
, "Usage: viLastLine screenId", TCL_STATIC
);
251 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
254 rval
= api_lline(sp
, &last
);
259 (void)sprintf(interp
->result
, "%lu", (unsigned long)last
);
265 * Set lineNumber to the text supplied.
267 * Tcl Command: viSetLine
268 * Usage: viSetLine screenId lineNumber text
271 tcl_sline(clientData
, interp
, argc
, argv
)
272 ClientData clientData
;
278 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
282 Tcl_SetResult(interp
,
283 "Usage: viSetLine screenId lineNumber text", TCL_STATIC
);
287 if (getscreenid(interp
, &sp
, argv
[1], NULL
) ||
288 getint(interp
, "line number", argv
[2], &lno
))
291 rval
= api_sline(sp
, (db_recno_t
)lno
, argv
[3], strlen(argv
[3]));
294 return (rval
? TCL_ERROR
: TCL_OK
);
299 * Return the mark's cursor position as a list with two elements.
302 * Tcl Command: viGetMark
303 * Usage: viGetMark screenId mark
306 tcl_getmark(clientData
, interp
, argc
, argv
)
307 ClientData clientData
;
314 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
319 Tcl_SetResult(interp
,
320 "Usage: viGetMark screenId mark", TCL_STATIC
);
324 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
327 rval
= api_getmark(sp
, (int)argv
[2][0], &cursor
);
333 (void)snprintf(buf
, sizeof(buf
), "%lu", (u_long
)cursor
.lno
);
334 Tcl_AppendElement(interp
, buf
);
335 (void)snprintf(buf
, sizeof(buf
), "%lu", (u_long
)cursor
.cno
);
336 Tcl_AppendElement(interp
, buf
);
342 * Set the mark to the line and column numbers supplied.
344 * Tcl Command: viSetMark
345 * Usage: viSetMark screenId mark line column
348 tcl_setmark(clientData
, interp
, argc
, argv
)
349 ClientData clientData
;
356 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
360 Tcl_SetResult(interp
,
361 "Usage: viSetMark screenId mark line column", TCL_STATIC
);
365 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
367 if (getint(interp
, "line number", argv
[3], &i
))
370 if (getint(interp
, "column number", argv
[4], &i
))
374 rval
= api_setmark(sp
, (int)argv
[2][0], &cursor
);
377 return (rval
? TCL_ERROR
: TCL_OK
);
382 * Return the current cursor position as a list with two elements.
385 * Tcl Command: viGetCursor
386 * Usage: viGetCursor screenId
389 tcl_getcursor(clientData
, interp
, argc
, argv
)
390 ClientData clientData
;
397 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
402 Tcl_SetResult(interp
,
403 "Usage: viGetCursor screenId", TCL_STATIC
);
407 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
410 rval
= api_getcursor(sp
, &cursor
);
416 (void)snprintf(buf
, sizeof(buf
), "%lu", (u_long
)cursor
.lno
);
417 Tcl_AppendElement(interp
, buf
);
418 (void)snprintf(buf
, sizeof(buf
), "%lu", (u_long
)cursor
.cno
);
419 Tcl_AppendElement(interp
, buf
);
425 * Set the cursor to the line and column numbers supplied.
427 * Tcl Command: viSetCursor
428 * Usage: viSetCursor screenId line column
431 tcl_setcursor(clientData
, interp
, argc
, argv
)
432 ClientData clientData
;
439 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
443 Tcl_SetResult(interp
,
444 "Usage: viSetCursor screenId line column", TCL_STATIC
);
448 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
450 if (getint(interp
, "screen id", argv
[2], &i
))
453 if (getint(interp
, "screen id", argv
[3], &i
))
457 rval
= api_setcursor(sp
, &cursor
);
460 return (rval
? TCL_ERROR
: TCL_OK
);
465 * Set the message line to text.
468 * Usage: viMsg screenId text
471 tcl_msg(clientData
, interp
, argc
, argv
)
472 ClientData clientData
;
480 Tcl_SetResult(interp
, "Usage: viMsg screenId text", TCL_STATIC
);
484 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
486 api_imessage(sp
, argv
[2]);
493 * Create a new screen. If a filename is specified then the screen
494 * is opened with that file.
496 * Tcl Command: viNewScreen
497 * Usage: viNewScreen screenId [file]
500 tcl_iscreen(clientData
, interp
, argc
, argv
)
501 ClientData clientData
;
507 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
510 if (argc
!= 2 && argc
!= 3) {
511 Tcl_SetResult(interp
,
512 "Usage: viNewScreen screenId [file]", TCL_STATIC
);
516 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
519 rval
= api_edit(sp
, argv
[2], &nsp
, 1);
525 (void)sprintf(interp
->result
, "%d", nsp
->id
);
533 * Tcl Command: viEndScreen
534 * Usage: viEndScreen screenId
537 tcl_escreen(clientData
, interp
, argc
, argv
)
538 ClientData clientData
;
544 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
548 Tcl_SetResult(interp
,
549 "Usage: viEndScreen screenId", TCL_STATIC
);
553 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
556 rval
= api_escreen(sp
);
559 return (rval
? TCL_ERROR
: TCL_OK
);
564 * Change the current focus to screen.
566 * Tcl Command: viSwitchScreen
567 * Usage: viSwitchScreen screenId screenId
570 tcl_swscreen(clientData
, interp
, argc
, argv
)
571 ClientData clientData
;
577 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
581 Tcl_SetResult(interp
,
582 "Usage: viSwitchScreen cur_screenId new_screenId",
587 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
589 if (getscreenid(interp
, &new, argv
[2], NULL
))
592 rval
= api_swscreen(sp
, new);
595 return (rval
? TCL_ERROR
: TCL_OK
);
600 * Associate a key with a tcl procedure.
602 * Tcl Command: viMapKey
603 * Usage: viMapKey screenId key tclproc
606 tcl_map(clientData
, interp
, argc
, argv
)
607 ClientData clientData
;
613 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
618 Tcl_SetResult(interp
,
619 "Usage: viMapKey screenId key tclproc", TCL_STATIC
);
623 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
626 (void)snprintf(command
, sizeof(command
), ":tcl %s\n", argv
[3]);
627 rval
= api_map(sp
, argv
[2], command
, strlen(command
));
630 return (rval
? TCL_ERROR
: TCL_OK
);
637 * Tcl Command: viUnmapKey
638 * Usage: viUnmMapKey screenId key
641 tcl_unmap(clientData
, interp
, argc
, argv
)
642 ClientData clientData
;
648 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
652 Tcl_SetResult(interp
,
653 "Usage: viUnmapKey screenId key", TCL_STATIC
);
657 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
660 rval
= api_unmap(sp
, argv
[2]);
663 return (rval
? TCL_ERROR
: TCL_OK
);
670 * Tcl Command: viSetOpt
671 * Usage: viSetOpt screenId command
674 tcl_opts_set(clientData
, interp
, argc
, argv
)
675 ClientData clientData
;
681 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
686 Tcl_SetResult(interp
,
687 "Usage: viSetOpt screenId command", TCL_STATIC
);
691 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
694 /*rval = api_opts_set(sp, argv[2]);*/
695 MALLOC(sp
, setting
, char *, strlen(argv
[2])+6);
696 strcpy(setting
, ":set ");
697 strcpy(setting
+5, argv
[2]);
698 rval
=api_run_str(sp
, setting
);
702 return (rval
? TCL_ERROR
: TCL_OK
);
707 Return the value of an option.
709 * Tcl Command: viGetOpt
710 * Usage: viGetOpt screenId option
713 tcl_opts_get(clientData
, interp
, argc
, argv
)
714 ClientData clientData
;
720 void (*scr_msg
) __P((SCR
*, mtype_t
, char *, size_t));
725 Tcl_SetResult(interp
,
726 "Usage: viGetOpt screenId option", TCL_STATIC
);
730 if (getscreenid(interp
, &sp
, argv
[1], NULL
))
733 rval
= api_opts_get(sp
, argv
[2], &value
, NULL
);
738 Tcl_SetResult(interp
, value
, TCL_DYNAMIC
);
744 * Create the TCL commands used by nvi.
746 * PUBLIC: int tcl_init __P((GS *));
752 gp
->tcl_interp
= Tcl_CreateInterp();
753 if (Tcl_Init(gp
->tcl_interp
) == TCL_ERROR
)
756 #define TCC(name, function) { \
757 Tcl_CreateCommand(gp->tcl_interp, name, function, \
758 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); \
760 TCC("viAppendLine", tcl_aline
);
761 TCC("viDelLine", tcl_dline
);
762 TCC("viEndScreen", tcl_escreen
);
763 TCC("viFindScreen", tcl_fscreen
);
764 TCC("viGetCursor", tcl_getcursor
);
765 TCC("viGetLine", tcl_gline
);
766 TCC("viGetMark", tcl_getmark
);
767 TCC("viGetOpt", tcl_opts_get
);
768 TCC("viInsertLine", tcl_iline
);
769 TCC("viLastLine", tcl_lline
);
770 TCC("viMapKey", tcl_map
);
771 TCC("viMsg", tcl_msg
);
772 TCC("viNewScreen", tcl_iscreen
);
773 TCC("viSetCursor", tcl_setcursor
);
774 TCC("viSetLine", tcl_sline
);
775 TCC("viSetMark", tcl_setmark
);
776 TCC("viSetOpt", tcl_opts_set
);
777 TCC("viSwitchScreen", tcl_swscreen
);
778 TCC("viUnmapKey", tcl_unmap
);
785 * Get the specified screen pointer.
788 * This is fatal. We can't post a message into vi that we're unable to find
789 * the screen without first finding the screen... So, this must be the first
790 * thing a Tcl routine does, and, if it fails, the last as well.
793 getscreenid(interp
, spp
, id
, name
)
801 if (id
!= NULL
&& getint(interp
, "screen id", id
, &scr_no
))
803 if ((*spp
= api_fscreen(scr_no
, name
)) == NULL
) {
804 (void)snprintf(buf
, sizeof(buf
),
805 "unknown screen id: %s", name
== NULL
? id
: name
);
806 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
817 * This code assumes that both db_recno_t and size_t are larger than ints.
820 getint(interp
, msg
, s
, intp
)
827 if (Tcl_GetInt(interp
, s
, intp
) == TCL_ERROR
)
830 (void)snprintf(buf
, sizeof(buf
),
831 "illegal %s %s: may not be negative", msg
, s
);
832 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
840 * Tcl message routine so that error messages are processed in
844 msghandler(sp
, mtype
, msg
, len
)
850 /* Replace the trailing <newline> with an EOS. */
853 Tcl_SetResult(sp
->gp
->tcl_interp
, msg
, TCL_VOLATILE
);