xref: /netbsd-src/external/bsd/nvi/dist/common/api.c (revision 2f698edb5c1cb2dcd9e762b0abb50c41dde8b6b7)
1 /*	$NetBSD: api.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */
2 /*-
3  * Copyright (c) 1992, 1993, 1994
4  *	The Regents of the University of California.  All rights reserved.
5  * Copyright (c) 1992, 1993, 1994, 1995, 1996
6  *	Keith Bostic.  All rights reserved.
7  * Copyright (c) 1995
8  *	George V. Neville-Neil. All rights reserved.
9  *
10  * See the LICENSE file for redistribution information.
11  */
12 
13 #include "config.h"
14 
15 #include <sys/cdefs.h>
16 #if 0
17 #ifndef lint
18 static const char sccsid[] = "Id: api.c,v 8.40 2002/06/08 19:30:33 skimo Exp  (Berkeley) Date: 2002/06/08 19:30:33 ";
19 #endif /* not lint */
20 #else
21 __RCSID("$NetBSD: api.c,v 1.4 2014/01/26 21:43:45 christos Exp $");
22 #endif
23 
24 #include <sys/types.h>
25 #include <sys/queue.h>
26 #include <sys/time.h>
27 
28 #include <bitstring.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <termios.h>
34 #include <unistd.h>
35 
36 #include "../common/common.h"
37 #include "../ex/tag.h"
38 
39 extern GS *__global_list;			/* XXX */
40 
41 /*
42  * api_fscreen --
43  *	Return a pointer to the screen specified by the screen id
44  *	or a file name.
45  *
46  * PUBLIC: SCR *api_fscreen __P((int, char *));
47  */
48 SCR *
api_fscreen(int id,char * name)49 api_fscreen(int id, char *name)
50 {
51 	GS *gp;
52 	SCR *tsp;
53 	WIN *wp;
54 
55 	gp = __global_list;
56 
57 	/* Search the displayed lists. */
58 	TAILQ_FOREACH(wp, &gp->dq, q)
59 		TAILQ_FOREACH(tsp, &wp->scrq, q)
60 			if (name == NULL) {
61 				if (id == tsp->id)
62 					return (tsp);
63 			} else if (!strcmp(name, tsp->frp->name))
64 				return (tsp);
65 
66 	/* Search the hidden list. */
67 	TAILQ_FOREACH (tsp,  &gp->hq, q)
68 		if (name == NULL) {
69 			if (id == tsp->id)
70 				return (tsp);
71 		} else if (!strcmp(name, tsp->frp->name))
72 			return (tsp);
73 	return (NULL);
74 }
75 
76 /*
77  * api_aline --
78  *	Append a line.
79  *
80  * PUBLIC: int api_aline __P((SCR *, db_recno_t, char *, size_t));
81  */
82 int
api_aline(SCR * sp,db_recno_t lno,char * line,size_t len)83 api_aline(SCR *sp, db_recno_t lno, char *line, size_t len)
84 {
85 	size_t wblen;
86 	const CHAR_T *wbp;
87 
88 	CHAR2INT(sp, line, len, wbp, wblen);
89 
90 	return (db_append(sp, 1, lno, wbp, wblen));
91 }
92 
93 /*
94  * api_extend --
95  *	Extend file.
96  *
97  * PUBLIC: int api_extend __P((SCR *, db_recno_t));
98  */
99 int
api_extend(SCR * sp,db_recno_t lno)100 api_extend(SCR *sp, db_recno_t lno)
101 {
102 	db_recno_t lastlno;
103 	if (db_last(sp, &lastlno))
104 	    return 1;
105 	while(lastlno < lno)
106 	    if (db_append(sp, 1, lastlno++, NULL, 0))
107 		return 1;
108 	return 0;
109 }
110 
111 /*
112  * api_dline --
113  *	Delete a line.
114  *
115  * PUBLIC: int api_dline __P((SCR *, db_recno_t));
116  */
117 int
api_dline(SCR * sp,db_recno_t lno)118 api_dline(SCR *sp, db_recno_t lno)
119 {
120 	if (db_delete(sp, lno))
121 		return 1;
122 	/* change current line if deleted line is that one
123 	 * or one berfore that
124 	 */
125 	if (sp->lno >= lno && sp->lno > 1)
126 		sp->lno--;
127 	return 0;
128 }
129 
130 /*
131  * api_gline --
132  *	Get a line.
133  *
134  * PUBLIC: int api_gline __P((SCR *, db_recno_t, CHAR_T **, size_t *));
135  */
136 int
api_gline(SCR * sp,db_recno_t lno,CHAR_T ** linepp,size_t * lenp)137 api_gline(SCR *sp, db_recno_t lno, CHAR_T **linepp, size_t *lenp)
138 {
139 	int isempty;
140 
141 	if (db_eget(sp, lno, linepp, lenp, &isempty)) {
142 		if (isempty)
143 			msgq(sp, M_ERR, "209|The file is empty");
144 		return (1);
145 	}
146 	return (0);
147 }
148 
149 /*
150  * api_iline --
151  *	Insert a line.
152  *
153  * PUBLIC: int api_iline __P((SCR *, db_recno_t, CHAR_T *, size_t));
154  */
155 int
api_iline(SCR * sp,db_recno_t lno,CHAR_T * line,size_t len)156 api_iline(SCR *sp, db_recno_t lno, CHAR_T *line, size_t len)
157 {
158 	return (db_insert(sp, lno, line, len));
159 }
160 
161 /*
162  * api_lline --
163  *	Return the line number of the last line in the file.
164  *
165  * PUBLIC: int api_lline __P((SCR *, db_recno_t *));
166  */
167 int
api_lline(SCR * sp,db_recno_t * lnop)168 api_lline(SCR *sp, db_recno_t *lnop)
169 {
170 	return (db_last(sp, lnop));
171 }
172 
173 /*
174  * api_sline --
175  *	Set a line.
176  *
177  * PUBLIC: int api_sline __P((SCR *, db_recno_t, CHAR_T *, size_t));
178  */
179 int
api_sline(SCR * sp,db_recno_t lno,CHAR_T * line,size_t len)180 api_sline(SCR *sp, db_recno_t lno, CHAR_T *line, size_t len)
181 {
182 	return (db_set(sp, lno, line, len));
183 }
184 
185 /*
186  * api_getmark --
187  *	Get the mark.
188  *
189  * PUBLIC: int api_getmark __P((SCR *, int, MARK *));
190  */
191 int
api_getmark(SCR * sp,int markname,MARK * mp)192 api_getmark(SCR *sp, int markname, MARK *mp)
193 {
194 	return (mark_get(sp, (ARG_CHAR_T)markname, mp, M_ERR));
195 }
196 
197 /*
198  * api_setmark --
199  *	Set the mark.
200  *
201  * PUBLIC: int api_setmark __P((SCR *, int, MARK *));
202  */
203 int
api_setmark(SCR * sp,int markname,MARK * mp)204 api_setmark(SCR *sp, int markname, MARK *mp)
205 {
206 	return (mark_set(sp, (ARG_CHAR_T)markname, mp, 1));
207 }
208 
209 /*
210  * api_nextmark --
211  *	Return the first mark if next not set, otherwise return the
212  *	subsequent mark.
213  *
214  * PUBLIC: int api_nextmark __P((SCR *, int, char *));
215  */
216 int
api_nextmark(SCR * sp,int next,char * namep)217 api_nextmark(SCR *sp, int next, char *namep)
218 {
219 	LMARK *mp;
220 
221 	mp = LIST_FIRST(&sp->ep->marks);
222 	if (next)
223 		for (; mp != NULL; mp = LIST_NEXT(mp, q))
224 			if (mp->name == *namep) {
225 				mp = LIST_NEXT(mp, q);
226 				break;
227 			}
228 	if (mp == NULL)
229 		return (1);
230 	*namep = mp->name;
231 	return (0);
232 }
233 
234 /*
235  * api_getcursor --
236  *	Get the cursor.
237  *
238  * PUBLIC: int api_getcursor __P((SCR *, MARK *));
239  */
240 int
api_getcursor(SCR * sp,MARK * mp)241 api_getcursor(SCR *sp, MARK *mp)
242 {
243 	mp->lno = sp->lno;
244 	mp->cno = sp->cno;
245 	return (0);
246 }
247 
248 /*
249  * api_setcursor --
250  *	Set the cursor.
251  *
252  * PUBLIC: int api_setcursor __P((SCR *, MARK *));
253  */
254 int
api_setcursor(SCR * sp,MARK * mp)255 api_setcursor(SCR *sp, MARK *mp)
256 {
257 	size_t len;
258 
259 	if (db_get(sp, mp->lno, DBG_FATAL, NULL, &len))
260 		return (1);
261 	if (mp->cno > len) {
262 		msgq(sp, M_ERR, "Cursor set to nonexistent column");
263 		return (1);
264 	}
265 
266 	/* Set the cursor. */
267 	sp->lno = mp->lno;
268 	sp->cno = mp->cno;
269 	return (0);
270 }
271 
272 /*
273  * api_emessage --
274  *	Print an error message.
275  *
276  * PUBLIC: void api_emessage __P((SCR *, char *));
277  */
278 void
api_emessage(SCR * sp,char * text)279 api_emessage(SCR *sp, 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(SCR * sp,char * text)291 api_imessage(SCR *sp, char *text)
292 {
293 	msgq(sp, M_INFO, "%s", text);
294 }
295 
296 /*
297  * api_edit
298  *	Create a new screen and return its id
299  *	or edit a new file in the current screen.
300  *
301  * PUBLIC: int api_edit __P((SCR *, char *, SCR **, int));
302  */
303 int
api_edit(SCR * sp,char * file,SCR ** spp,int newscreen)304 api_edit(SCR *sp, char *file, SCR **spp, int newscreen)
305 {
306 	EXCMD cmd;
307 	size_t wlen;
308 	const CHAR_T *wp;
309 
310 	if (file) {
311 		ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
312 		CHAR2INT(sp, file, strlen(file) + 1, wp, wlen);
313 		argv_exp0(sp, &cmd, wp, wlen - 1 /* terminating 0 */);
314 	} else
315 		ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
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 __P((SCR *));
329  */
330 int
api_escreen(SCR * sp)331 api_escreen(SCR *sp)
332 {
333 	EXCMD cmd;
334 
335 	/*
336 	 * XXX
337 	 * If the interpreter exits anything other than the current
338 	 * screen, vi isn't going to update everything correctly.
339 	 */
340 	ex_cinit(sp, &cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0);
341 	return (cmd.cmd->fn(sp, &cmd));
342 }
343 
344 /*
345  * api_swscreen --
346  *    Switch to a new screen.
347  *
348  * PUBLIC: int api_swscreen __P((SCR *, SCR *));
349  */
350 int
api_swscreen(SCR * sp,SCR * new)351 api_swscreen(SCR *sp, SCR *new)
352 {
353 	/*
354 	 * XXX
355 	 * If the interpreter switches from anything other than the
356 	 * current screen, vi isn't going to update everything correctly.
357 	 */
358 	sp->nextdisp = new;
359 	F_SET(sp, SC_SSWITCH);
360 
361 	return (0);
362 }
363 
364 /*
365  * api_map --
366  *	Map a key.
367  *
368  * PUBLIC: int api_map __P((SCR *, char *, char *, size_t));
369  */
370 int
api_map(SCR * sp,char * name,char * map,size_t len)371 api_map(SCR *sp, char *name, char *map, size_t len)
372 {
373 	EXCMD cmd;
374 	size_t wlen;
375 	const CHAR_T *wp;
376 
377 	ex_cinit(sp, &cmd, C_MAP, 0, OOBLNO, OOBLNO, 0);
378 	CHAR2INT(sp, name, strlen(name) + 1, wp, wlen);
379 	argv_exp0(sp, &cmd, wp, wlen - 1);
380 	CHAR2INT(sp, map, len, wp, wlen);
381 	argv_exp0(sp, &cmd, wp, wlen);
382 	return (cmd.cmd->fn(sp, &cmd));
383 }
384 
385 /*
386  * api_unmap --
387  *	Unmap a key.
388  *
389  * PUBLIC: int api_unmap __P((SCR *, char *));
390  */
391 int
api_unmap(SCR * sp,char * name)392 api_unmap(SCR *sp, char *name)
393 {
394 	EXCMD cmd;
395 	size_t wlen;
396 	const CHAR_T *wp;
397 
398 	ex_cinit(sp, &cmd, C_UNMAP, 0, OOBLNO, OOBLNO, 0);
399 	CHAR2INT(sp, name, strlen(name) + 1, wp, wlen);
400 	argv_exp0(sp, &cmd, wp, wlen - 1);
401 	return (cmd.cmd->fn(sp, &cmd));
402 }
403 
404 /*
405  * api_opts_get --
406  *	Return a option value as a string, in allocated memory.
407  *	If the option is of type boolean, boolvalue is (un)set
408  *	according to the value; otherwise boolvalue is -1.
409  *
410  * PUBLIC: int api_opts_get __P((SCR *, const CHAR_T *, char **, int *));
411  */
412 int
api_opts_get(SCR * sp,const CHAR_T * name,char ** value,int * boolvalue)413 api_opts_get(SCR *sp, const CHAR_T *name, char **value, int *boolvalue)
414 {
415 	OPTLIST const *op;
416 	int offset;
417 
418 	if ((op = opts_search(name)) == NULL) {
419 		opts_nomatch(sp, name);
420 		return (1);
421 	}
422 
423 	offset = op - optlist;
424 	if (boolvalue != NULL)
425 		*boolvalue = -1;
426 	switch (op->type) {
427 	case OPT_0BOOL:
428 	case OPT_1BOOL:
429 		MALLOC_RET(sp, *value, char *, STRLEN(op->name) + 2 + 1);
430 		(void)sprintf(*value,
431 		    "%s"WS, O_ISSET(sp, offset) ? "" : "no", op->name);
432 		if (boolvalue != NULL)
433 			*boolvalue = O_ISSET(sp, offset);
434 		break;
435 	case OPT_NUM:
436 		MALLOC_RET(sp, *value, char *, 20);
437 		(void)sprintf(*value, "%lu", (u_long)O_VAL(sp, offset));
438 		break;
439 	case OPT_STR:
440 		if (O_STR(sp, offset) == NULL) {
441 			MALLOC_RET(sp, *value, char *, 2);
442 			value[0][0] = '\0';
443 		} else {
444 			MALLOC_RET(sp,
445 			    *value, char *, strlen(O_STR(sp, offset)) + 1);
446 			(void)sprintf(*value, "%s", O_STR(sp, offset));
447 		}
448 		break;
449 	}
450 	return (0);
451 }
452 
453 /*
454  * api_opts_set --
455  *	Set options.
456  *
457  * PUBLIC: int api_opts_set __P((SCR *, const CHAR_T *, const char *, u_long, int));
458  */
459 int
api_opts_set(SCR * sp,const CHAR_T * name,const char * str_value,u_long num_value,int bool_value)460 api_opts_set(SCR *sp, const CHAR_T *name,
461 	     const char *str_value, u_long num_value, int bool_value)
462 {
463 	ARGS *ap[2], a, b;
464 	OPTLIST const *op;
465 	int rval;
466 	size_t blen;
467 	CHAR_T *bp;
468 
469 	if ((op = opts_search(name)) == NULL) {
470 		opts_nomatch(sp, name);
471 		return (1);
472 	}
473 
474 	switch (op->type) {
475 	case OPT_0BOOL:
476 	case OPT_1BOOL:
477 		GET_SPACE_RETW(sp, bp, blen, 64);
478 		a.len = SPRINTF(bp, 64, L("%s"WS), bool_value ? "" : "no", name);
479 		break;
480 	case OPT_NUM:
481 		GET_SPACE_RETW(sp, bp, blen, 64);
482 		a.len = SPRINTF(bp, 64, L(""WS"=%lu"), name, num_value);
483 		break;
484 	case OPT_STR:
485 		GET_SPACE_RETW(sp, bp, blen, 1024);
486 		a.len = SPRINTF(bp, 1024, L(""WS"=%s"), name, str_value);
487 		break;
488 	default:
489 		bp = NULL;
490 		break;
491 	}
492 
493 	a.bp = bp;
494 	b.len = 0;
495 	b.bp = NULL;
496 	ap[0] = &a;
497 	ap[1] = &b;
498 	rval = opts_set(sp, ap, NULL);
499 
500 	FREE_SPACEW(sp, bp, blen);
501 
502 	return (rval);
503 }
504 
505 /*
506  * api_run_str --
507  *      Execute a string as an ex command.
508  *
509  * PUBLIC: int api_run_str __P((SCR *, char *));
510  */
511 int
api_run_str(SCR * sp,char * cmd)512 api_run_str(SCR *sp, char *cmd)
513 {
514 	size_t wlen;
515 	const CHAR_T *wp;
516 
517 	CHAR2INT(sp, cmd, strlen(cmd)+1, wp, wlen);
518 	return (ex_run_str(sp, NULL, wp, wlen - 1, 0, 0));
519 }
520 
521 /*
522  * PUBLIC: TAGQ * api_tagq_new __P((SCR*, char*));
523  */
524 TAGQ *
api_tagq_new(SCR * sp,char * tag)525 api_tagq_new(SCR *sp, char *tag)
526 {
527 	TAGQ *tqp;
528 	size_t len;
529 
530 	/* Allocate and initialize the tag queue structure. */
531 	len = strlen(tag);
532 	CALLOC_GOTO(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + len + 1);
533 	TAILQ_INIT(&tqp->tagq);
534 	tqp->tag = tqp->buf;
535 	memcpy(tqp->tag, tag, (tqp->tlen = len) + 1);
536 
537 	return tqp;
538 
539 alloc_err:
540 	return (NULL);
541 }
542 
543 /*
544  * PUBLIC: void api_tagq_add __P((SCR*, TAGQ*, char*, char *, char *));
545  */
546 void
api_tagq_add(SCR * sp,TAGQ * tqp,char * filename,char * search,char * msg)547 api_tagq_add(SCR *sp, TAGQ *tqp, char *filename, char *search, char *msg)
548 {
549 	TAG *tp;
550 	const CHAR_T *wp;
551 	size_t wlen;
552 	size_t flen = strlen(filename);
553 	size_t slen = strlen(search);
554 	size_t mlen = strlen(msg);
555 
556 	CALLOC_GOTO(sp, tp, TAG *, 1,
557 		    sizeof(TAG) - 1 + flen + 1 +
558 		    (slen + 1 + mlen + 1) * sizeof(CHAR_T));
559 	tp->fname = (char *)tp->buf;
560 	memcpy(tp->fname, filename, flen + 1);
561 	tp->fnlen = flen;
562 	tp->search = (CHAR_T *)((char *)tp->fname + flen + 1);
563 	CHAR2INT(sp, search, slen + 1, wp, wlen);
564 	MEMCPYW(tp->search, wp, wlen);
565 	tp->slen = slen;
566 	tp->msg = tp->search + slen + 1;
567 	CHAR2INT(sp, msg, mlen + 1, wp, wlen);
568 	MEMCPYW(tp->msg, wp, wlen);
569 	tp->mlen = mlen;
570 	TAILQ_INSERT_TAIL(&tqp->tagq, tp, q);
571 
572 alloc_err:
573 	return;
574 }
575 
576 /*
577  * PUBLIC: int api_tagq_push __P((SCR*, TAGQ**));
578  */
579 int
api_tagq_push(SCR * sp,TAGQ ** tqpp)580 api_tagq_push(SCR *sp, TAGQ **tqpp)
581 {
582 	TAGQ *tqp;
583 
584 	tqp = *tqpp;
585 
586 	*tqpp = 0;
587 
588 	/* Check to see if we found anything. */
589 	if (TAILQ_EMPTY(&tqp->tagq)) {
590 		free(tqp);
591 		return 0;
592 	}
593 
594 	tqp->current = TAILQ_FIRST(&tqp->tagq);
595 
596 	if (tagq_push(sp, tqp, 0, 0))
597 		return 1;
598 
599 	return (0);
600 }
601 
602 /*
603  * PUBLIC: void api_tagq_free __P((SCR*, TAGQ*));
604  */
605 void
api_tagq_free(SCR * sp,TAGQ * tqp)606 api_tagq_free(SCR *sp, TAGQ *tqp)
607 {
608 	if (tqp)
609 		tagq_free(sp, tqp);
610 }
611