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