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