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, 1996
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[] = "@(#)api.c	8.26 (Berkeley) 10/14/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 <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <termios.h>
28 #include <unistd.h>
29 
30 #include "../common/common.h"
31 
32 extern GS *__global_list;			/* XXX */
33 
34 /*
35  * api_fscreen --
36  *	Return a pointer to the screen specified by the screen id
37  *	or a file name.
38  *
39  * PUBLIC: SCR *api_fscreen __P((int, char *));
40  */
41 SCR *
api_fscreen(id,name)42 api_fscreen(id, name)
43 	int id;
44 	char *name;
45 {
46 	GS *gp;
47 	SCR *tsp;
48 
49 	gp = __global_list;
50 
51 	/* Search the displayed list. */
52 	for (tsp = gp->dq.cqh_first;
53 	    tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
54 		if (name == NULL) {
55 			if (id == tsp->id)
56 				return (tsp);
57 		} else if (!strcmp(name, tsp->frp->name))
58 			return (tsp);
59 
60 	/* Search the hidden list. */
61 	for (tsp = gp->hq.cqh_first;
62 	    tsp != (void *)&gp->hq; tsp = tsp->q.cqe_next)
63 		if (name == NULL) {
64 			if (id == tsp->id)
65 				return (tsp);
66 		} else if (!strcmp(name, tsp->frp->name))
67 			return (tsp);
68 	return (NULL);
69 }
70 
71 /*
72  * api_aline --
73  *	Append a line.
74  *
75  * PUBLIC: int api_aline __P((SCR *, recno_t, char *, size_t));
76  */
77 int
api_aline(sp,lno,line,len)78 api_aline(sp, lno, line, len)
79 	SCR *sp;
80 	recno_t lno;
81 	char *line;
82 	size_t len;
83 {
84 	return (db_append(sp, 1, lno, line, len));
85 }
86 
87 /*
88  * api_dline --
89  *	Delete a line.
90  *
91  * PUBLIC: int api_dline __P((SCR *, recno_t));
92  */
93 int
api_dline(sp,lno)94 api_dline(sp, lno)
95 	SCR *sp;
96 	recno_t lno;
97 {
98 	return (db_delete(sp, lno));
99 }
100 
101 /*
102  * api_gline --
103  *	Get a line.
104  *
105  * PUBLIC: int api_gline __P((SCR *, recno_t, char **, size_t *));
106  */
107 int
api_gline(sp,lno,linepp,lenp)108 api_gline(sp, lno, linepp, lenp)
109 	SCR *sp;
110 	recno_t lno;
111 	char **linepp;
112 	size_t *lenp;
113 {
114 	int isempty;
115 
116 	if (db_eget(sp, lno, linepp, lenp, &isempty)) {
117 		if (isempty)
118 			msgq(sp, M_ERR, "209|The file is empty");
119 		return (1);
120 	}
121 	return (0);
122 }
123 
124 /*
125  * api_iline --
126  *	Insert a line.
127  *
128  * PUBLIC: int api_iline __P((SCR *, recno_t, char *, size_t));
129  */
130 int
api_iline(sp,lno,line,len)131 api_iline(sp, lno, line, len)
132 	SCR *sp;
133 	recno_t lno;
134 	char *line;
135 	size_t len;
136 {
137 	return (db_insert(sp, lno, line, len));
138 }
139 
140 /*
141  * api_lline --
142  *	Return the line number of the last line in the file.
143  *
144  * PUBLIC: int api_lline __P((SCR *, recno_t *));
145  */
146 int
api_lline(sp,lnop)147 api_lline(sp, lnop)
148 	SCR *sp;
149 	recno_t *lnop;
150 {
151 	return (db_last(sp, lnop));
152 }
153 
154 /*
155  * api_sline --
156  *	Set a line.
157  *
158  * PUBLIC: int api_sline __P((SCR *, recno_t, char *, size_t));
159  */
160 int
api_sline(sp,lno,line,len)161 api_sline(sp, lno, line, len)
162 	SCR *sp;
163 	recno_t lno;
164 	char *line;
165 	size_t len;
166 {
167 	return (db_set(sp, lno, line, len));
168 }
169 
170 /*
171  * api_getmark --
172  *	Get the mark.
173  *
174  * PUBLIC: int api_getmark __P((SCR *, int, MARK *));
175  */
176 int
api_getmark(sp,markname,mp)177 api_getmark(sp, markname, mp)
178 	SCR *sp;
179 	int markname;
180 	MARK *mp;
181 {
182 	return (mark_get(sp, (ARG_CHAR_T)markname, mp, M_ERR));
183 }
184 
185 /*
186  * api_setmark --
187  *	Set the mark.
188  *
189  * PUBLIC: int api_setmark __P((SCR *, int, MARK *));
190  */
191 int
api_setmark(sp,markname,mp)192 api_setmark(sp, markname, mp)
193 	SCR *sp;
194 	int markname;
195 	MARK *mp;
196 {
197 	return (mark_set(sp, (ARG_CHAR_T)markname, mp, 1));
198 }
199 
200 /*
201  * api_nextmark --
202  *	Return the first mark if next not set, otherwise return the
203  *	subsequent mark.
204  *
205  * PUBLIC: int api_nextmark __P((SCR *, int, char *));
206  */
207 int
api_nextmark(sp,next,namep)208 api_nextmark(sp, next, namep)
209 	SCR *sp;
210 	int next;
211 	char *namep;
212 {
213 	LMARK *mp;
214 
215 	mp = sp->ep->marks.lh_first;
216 	if (next)
217 		for (; mp != NULL; mp = mp->q.le_next)
218 			if (mp->name == *namep) {
219 				mp = mp->q.le_next;
220 				break;
221 			}
222 	if (mp == NULL)
223 		return (1);
224 	*namep = mp->name;
225 	return (0);
226 }
227 
228 /*
229  * api_getcursor --
230  *	Get the cursor.
231  *
232  * PUBLIC: int api_getcursor __P((SCR *, MARK *));
233  */
234 int
api_getcursor(sp,mp)235 api_getcursor(sp, mp)
236 	SCR *sp;
237 	MARK *mp;
238 {
239 	mp->lno = sp->lno;
240 	mp->cno = sp->cno;
241 	return (0);
242 }
243 
244 /*
245  * api_setcursor --
246  *	Set the cursor.
247  *
248  * PUBLIC: int api_setcursor __P((SCR *, MARK *));
249  */
250 int
api_setcursor(sp,mp)251 api_setcursor(sp, mp)
252 	SCR *sp;
253 	MARK *mp;
254 {
255 	size_t len;
256 
257 	if (db_get(sp, mp->lno, DBG_FATAL, NULL, &len))
258 		return (1);
259 	if (mp->cno < 0 || mp->cno > len) {
260 		msgq(sp, M_ERR, "Cursor set to nonexistent column");
261 		return (1);
262 	}
263 
264 	/* Set the cursor. */
265 	sp->lno = mp->lno;
266 	sp->cno = mp->cno;
267 	return (0);
268 }
269 
270 /*
271  * api_emessage --
272  *	Print an error message.
273  *
274  * PUBLIC: void api_emessage __P((SCR *, char *));
275  */
276 void
api_emessage(sp,text)277 api_emessage(sp, text)
278 	SCR *sp;
279 	char *text;
280 {
281 	msgq(sp, M_ERR, "%s", text);
282 }
283 
284 /*
285  * api_imessage --
286  *	Print an informational message.
287  *
288  * PUBLIC: void api_imessage __P((SCR *, char *));
289  */
290 void
api_imessage(sp,text)291 api_imessage(sp, text)
292 	SCR *sp;
293 	char *text;
294 {
295 	msgq(sp, M_INFO, "%s", text);
296 }
297 
298 /*
299  * api_edit
300  *	Create a new screen and return its id
301  *	or edit a new file in the current screen.
302  *
303  * PUBLIC: int api_edit __P((SCR *, char *, SCR **, int));
304  */
305 int
api_edit(sp,file,spp,newscreen)306 api_edit(sp, file, spp, newscreen)
307 	SCR *sp;
308 	char *file;
309 	SCR **spp;
310 	int newscreen;
311 {
312 	ARGS *ap[2], a;
313 	EXCMD cmd;
314 
315 	if (file) {
316 		ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, ap);
317 		ex_cadd(&cmd, &a, file, strlen(file));
318 	} else
319 		ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, NULL);
320 	if (newscreen)
321 		cmd.flags |= E_NEWSCREEN;		/* XXX */
322 	if (cmd.cmd->fn(sp, &cmd))
323 		return (1);
324 	*spp = sp->nextdisp;
325 	return (0);
326 }
327 
328 /*
329  * api_escreen
330  *	End a screen.
331  *
332  * PUBLIC: int api_escreen __P((SCR *));
333  */
334 int
api_escreen(sp)335 api_escreen(sp)
336 	SCR *sp;
337 {
338 	EXCMD cmd;
339 
340 	/*
341 	 * XXX
342 	 * If the interpreter exits anything other than the current
343 	 * screen, vi isn't going to update everything correctly.
344 	 */
345 	ex_cinit(&cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0, NULL);
346 	return (cmd.cmd->fn(sp, &cmd));
347 }
348 
349 /*
350  * api_swscreen --
351  *    Switch to a new screen.
352  *
353  * PUBLIC: int api_swscreen __P((SCR *, SCR *));
354  */
355 int
api_swscreen(sp,new)356 api_swscreen(sp, new)
357       SCR *sp, *new;
358 {
359 	/*
360 	 * XXX
361 	 * If the interpreter switches from anything other than the
362 	 * current screen, vi isn't going to update everything correctly.
363 	 */
364 	sp->nextdisp = new;
365 	F_SET(sp, SC_SSWITCH);
366 
367 	return (0);
368 }
369 
370 /*
371  * api_map --
372  *	Map a key.
373  *
374  * PUBLIC: int api_map __P((SCR *, char *, char *, size_t));
375  */
376 int
api_map(sp,name,map,len)377 api_map(sp, name, map, len)
378 	SCR *sp;
379 	char *name, *map;
380 	size_t len;
381 {
382 	ARGS *ap[3], a, b;
383 	EXCMD cmd;
384 
385 	ex_cinit(&cmd, C_MAP, 0, OOBLNO, OOBLNO, 0, ap);
386 	ex_cadd(&cmd, &a, name, strlen(name));
387 	ex_cadd(&cmd, &b, map, len);
388 	return (cmd.cmd->fn(sp, &cmd));
389 }
390 
391 /*
392  * api_unmap --
393  *	Unmap a key.
394  *
395  * PUBLIC: int api_unmap __P((SCR *, char *));
396  */
397 int
api_unmap(sp,name)398 api_unmap(sp, name)
399 	SCR *sp;
400 	char *name;
401 {
402 	ARGS *ap[2], a;
403 	EXCMD cmd;
404 
405 	ex_cinit(&cmd, C_UNMAP, 0, OOBLNO, OOBLNO, 0, ap);
406 	ex_cadd(&cmd, &a, name, strlen(name));
407 	return (cmd.cmd->fn(sp, &cmd));
408 }
409 
410 /*
411  * api_opts_get --
412  *	Return a option value as a string, in allocated memory.
413  *	If the option is of type boolean, boolvalue is (un)set
414  *	according to the value; otherwise boolvalue is -1.
415  *
416  * PUBLIC: int api_opts_get __P((SCR *, char *, char **, int *));
417  */
418 int
api_opts_get(sp,name,value,boolvalue)419 api_opts_get(sp, name, value, boolvalue)
420 	SCR *sp;
421 	char *name, **value;
422 	int *boolvalue;
423 {
424 	OPTLIST const *op;
425 	int offset;
426 
427 	if ((op = opts_search(name)) == NULL) {
428 		opts_nomatch(sp, name);
429 		return (1);
430 	}
431 
432 	offset = op - optlist;
433 	if (boolvalue != NULL)
434 		*boolvalue = -1;
435 	switch (op->type) {
436 	case OPT_0BOOL:
437 	case OPT_1BOOL:
438 		MALLOC_RET(sp, *value, char *, strlen(op->name) + 2 + 1);
439 		(void)sprintf(*value,
440 		    "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name);
441 		if (boolvalue != NULL)
442 			*boolvalue = O_ISSET(sp, offset);
443 		break;
444 	case OPT_NUM:
445 		MALLOC_RET(sp, *value, char *, 20);
446 		(void)sprintf(*value, "%lu", (u_long)O_VAL(sp, offset));
447 		break;
448 	case OPT_STR:
449 		if (O_STR(sp, offset) == NULL) {
450 			MALLOC_RET(sp, *value, char *, 2);
451 			value[0] = '\0';
452 		} else {
453 			MALLOC_RET(sp,
454 			    *value, char *, strlen(O_STR(sp, offset)) + 1);
455 			(void)sprintf(*value, "%s", O_STR(sp, offset));
456 		}
457 		break;
458 	}
459 	return (0);
460 }
461 
462 /*
463  * api_opts_set --
464  *	Set options.
465  *
466  * PUBLIC: int api_opts_set __P((SCR *, char *, char *, u_long, int));
467  */
468 int
api_opts_set(sp,name,str_value,num_value,bool_value)469 api_opts_set(sp, name, str_value, num_value, bool_value)
470 	SCR *sp;
471 	char *name, *str_value;
472 	u_long num_value;
473 	int bool_value;
474 {
475 	ARGS *ap[2], a, b;
476 	OPTLIST const *op;
477 	int rval;
478 	size_t blen;
479 	char *bp;
480 
481 	if ((op = opts_search(name)) == NULL) {
482 		opts_nomatch(sp, name);
483 		return (1);
484 	}
485 
486 	switch (op->type) {
487 	case OPT_0BOOL:
488 	case OPT_1BOOL:
489 		GET_SPACE_RET(sp, bp, blen, 64);
490 		a.len = snprintf(bp, 64, "%s%s", bool_value ? "" : "no", name);
491 		break;
492 	case OPT_NUM:
493 		GET_SPACE_RET(sp, bp, blen, 64);
494 		a.len = snprintf(bp, 64, "%s=%lu", name, num_value);
495 		break;
496 	case OPT_STR:
497 		GET_SPACE_RET(sp, bp, blen, 1024);
498 		a.len = snprintf(bp, 1024, "%s=%s", name, str_value);
499 		break;
500 	}
501 	a.bp = bp;
502 	b.len = 0;
503 	b.bp = NULL;
504 	ap[0] = &a;
505 	ap[1] = &b;
506 	rval = opts_set(sp, ap, NULL);
507 
508 	FREE_SPACE(sp, bp, blen);
509 
510 	return (rval);
511 }
512 
513 /*
514  * api_run_str --
515  *      Execute a string as an ex command.
516  *
517  * PUBLIC: int api_run_str __P((SCR *, char *));
518  */
519 int
api_run_str(sp,cmd)520 api_run_str(sp, cmd)
521 	SCR *sp;
522 	char *cmd;
523 {
524 	return (ex_run_str(sp, NULL, cmd, strlen(cmd), 0, 0));
525 }
526