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