Home | History | Annotate | Line # | Download | only in common
      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 *
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    606 api_tagq_free(SCR *sp, TAGQ *tqp)
    607 {
    608 	if (tqp)
    609 		tagq_free(sp, tqp);
    610 }
    611