reset screen offset of top line if it exceeds the number of screens
[nvi.git] / common / api.c
blob5e3db69bf25dc3d6e0936bbfcbae5b4d3510636f
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.
9 * See the LICENSE file for redistribution information.
12 #include "config.h"
14 #ifndef lint
15 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 $";
16 #endif /* not lint */
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/time.h>
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>
30 #include "../common/common.h"
31 #include "../ex/tag.h"
33 extern GS *__global_list; /* XXX */
36 * api_fscreen --
37 * Return a pointer to the screen specified by the screen id
38 * or a file name.
40 * PUBLIC: SCR *api_fscreen __P((int, char *));
42 SCR *
43 api_fscreen(int id, char *name)
45 GS *gp;
46 SCR *tsp;
47 WIN *wp;
49 gp = __global_list;
51 /* Search the displayed lists. */
52 for (wp = gp->dq.cqh_first;
53 wp != (void *)&gp->dq; wp = wp->q.cqe_next)
54 for (tsp = wp->scrq.cqh_first;
55 tsp != (void *)&wp->scrq; tsp = tsp->q.cqe_next)
56 if (name == NULL) {
57 if (id == tsp->id)
58 return (tsp);
59 } else if (!strcmp(name, tsp->frp->name))
60 return (tsp);
62 /* Search the hidden list. */
63 for (tsp = gp->hq.cqh_first;
64 tsp != (void *)&gp->hq; tsp = tsp->q.cqe_next)
65 if (name == NULL) {
66 if (id == tsp->id)
67 return (tsp);
68 } else if (!strcmp(name, tsp->frp->name))
69 return (tsp);
70 return (NULL);
74 * api_aline --
75 * Append a line.
77 * PUBLIC: int api_aline __P((SCR *, db_recno_t, char *, size_t));
79 int
80 api_aline(SCR *sp, db_recno_t lno, char *line, size_t len)
82 size_t wblen;
83 CHAR_T *wbp;
85 CHAR2INT(sp, line, len, wbp, wblen);
87 return (db_append(sp, 1, lno, wbp, wblen));
91 * api_extend --
92 * Extend file.
94 * PUBLIC: int api_extend __P((SCR *, db_recno_t));
96 int
97 api_extend(SCR *sp, db_recno_t lno)
99 db_recno_t lastlno;
100 if (db_last(sp, &lastlno))
101 return 1;
102 while(lastlno < lno)
103 if (db_append(sp, 1, lastlno++, NULL, 0))
104 return 1;
105 return 0;
109 * api_dline --
110 * Delete a line.
112 * PUBLIC: int api_dline __P((SCR *, db_recno_t));
115 api_dline(SCR *sp, db_recno_t lno)
117 if (db_delete(sp, lno))
118 return 1;
119 /* change current line if deleted line is that one
120 * or one berfore that
122 if (sp->lno >= lno && sp->lno > 1)
123 sp->lno--;
124 return 0;
128 * api_gline --
129 * Get a line.
131 * PUBLIC: int api_gline __P((SCR *, db_recno_t, CHAR_T **, size_t *));
134 api_gline(SCR *sp, db_recno_t lno, CHAR_T **linepp, size_t *lenp)
136 int isempty;
138 if (db_eget(sp, lno, linepp, lenp, &isempty)) {
139 if (isempty)
140 msgq(sp, M_ERR, "209|The file is empty");
141 return (1);
143 return (0);
147 * api_iline --
148 * Insert a line.
150 * PUBLIC: int api_iline __P((SCR *, db_recno_t, CHAR_T *, size_t));
153 api_iline(SCR *sp, db_recno_t lno, CHAR_T *line, size_t len)
155 return (db_insert(sp, lno, line, len));
159 * api_lline --
160 * Return the line number of the last line in the file.
162 * PUBLIC: int api_lline __P((SCR *, db_recno_t *));
165 api_lline(SCR *sp, db_recno_t *lnop)
167 return (db_last(sp, lnop));
171 * api_sline --
172 * Set a line.
174 * PUBLIC: int api_sline __P((SCR *, db_recno_t, CHAR_T *, size_t));
177 api_sline(SCR *sp, db_recno_t lno, CHAR_T *line, size_t len)
179 return (db_set(sp, lno, line, len));
183 * api_getmark --
184 * Get the mark.
186 * PUBLIC: int api_getmark __P((SCR *, int, MARK *));
189 api_getmark(SCR *sp, int markname, MARK *mp)
191 return (mark_get(sp, (ARG_CHAR_T)markname, mp, M_ERR));
195 * api_setmark --
196 * Set the mark.
198 * PUBLIC: int api_setmark __P((SCR *, int, MARK *));
201 api_setmark(SCR *sp, int markname, MARK *mp)
203 return (mark_set(sp, (ARG_CHAR_T)markname, mp, 1));
207 * api_nextmark --
208 * Return the first mark if next not set, otherwise return the
209 * subsequent mark.
211 * PUBLIC: int api_nextmark __P((SCR *, int, char *));
214 api_nextmark(SCR *sp, int next, char *namep)
216 LMARK *mp;
218 mp = sp->ep->marks.lh_first;
219 if (next)
220 for (; mp != NULL; mp = mp->q.le_next)
221 if (mp->name == *namep) {
222 mp = mp->q.le_next;
223 break;
225 if (mp == NULL)
226 return (1);
227 *namep = mp->name;
228 return (0);
232 * api_getcursor --
233 * Get the cursor.
235 * PUBLIC: int api_getcursor __P((SCR *, MARK *));
238 api_getcursor(SCR *sp, MARK *mp)
240 mp->lno = sp->lno;
241 mp->cno = sp->cno;
242 return (0);
246 * api_setcursor --
247 * Set the cursor.
249 * PUBLIC: int api_setcursor __P((SCR *, MARK *));
252 api_setcursor(SCR *sp, MARK *mp)
254 size_t len;
256 if (db_get(sp, mp->lno, DBG_FATAL, NULL, &len))
257 return (1);
258 if (mp->cno < 0 || mp->cno > len) {
259 msgq(sp, M_ERR, "Cursor set to nonexistent column");
260 return (1);
263 /* Set the cursor. */
264 sp->lno = mp->lno;
265 sp->cno = mp->cno;
266 return (0);
270 * api_emessage --
271 * Print an error message.
273 * PUBLIC: void api_emessage __P((SCR *, char *));
275 void
276 api_emessage(SCR *sp, char *text)
278 msgq(sp, M_ERR, "%s", text);
282 * api_imessage --
283 * Print an informational message.
285 * PUBLIC: void api_imessage __P((SCR *, char *));
287 void
288 api_imessage(SCR *sp, char *text)
290 msgq(sp, M_INFO, "%s", text);
294 * api_edit
295 * Create a new screen and return its id
296 * or edit a new file in the current screen.
298 * PUBLIC: int api_edit __P((SCR *, char *, SCR **, int));
301 api_edit(SCR *sp, char *file, SCR **spp, int newscreen)
303 EXCMD cmd;
304 size_t wlen;
305 CHAR_T *wp;
307 if (file) {
308 ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
309 CHAR2INT(sp, file, strlen(file) + 1, wp, wlen);
310 argv_exp0(sp, &cmd, wp, wlen - 1 /* terminating 0 */);
311 } else
312 ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
313 if (newscreen)
314 cmd.flags |= E_NEWSCREEN; /* XXX */
315 if (cmd.cmd->fn(sp, &cmd))
316 return (1);
317 *spp = sp->nextdisp;
318 return (0);
322 * api_escreen
323 * End a screen.
325 * PUBLIC: int api_escreen __P((SCR *));
328 api_escreen(SCR *sp)
330 EXCMD cmd;
333 * XXX
334 * If the interpreter exits anything other than the current
335 * screen, vi isn't going to update everything correctly.
337 ex_cinit(sp, &cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0);
338 return (cmd.cmd->fn(sp, &cmd));
342 * api_swscreen --
343 * Switch to a new screen.
345 * PUBLIC: int api_swscreen __P((SCR *, SCR *));
348 api_swscreen(SCR *sp, SCR *new)
351 * XXX
352 * If the interpreter switches from anything other than the
353 * current screen, vi isn't going to update everything correctly.
355 sp->nextdisp = new;
356 F_SET(sp, SC_SSWITCH);
358 return (0);
362 * api_map --
363 * Map a key.
365 * PUBLIC: int api_map __P((SCR *, char *, char *, size_t));
368 api_map(SCR *sp, char *name, char *map, size_t len)
370 EXCMD cmd;
371 size_t wlen;
372 CHAR_T *wp;
374 ex_cinit(sp, &cmd, C_MAP, 0, OOBLNO, OOBLNO, 0);
375 CHAR2INT(sp, name, strlen(name) + 1, wp, wlen);
376 argv_exp0(sp, &cmd, wp, wlen - 1);
377 CHAR2INT(sp, map, len, wp, wlen);
378 argv_exp0(sp, &cmd, wp, wlen);
379 return (cmd.cmd->fn(sp, &cmd));
383 * api_unmap --
384 * Unmap a key.
386 * PUBLIC: int api_unmap __P((SCR *, char *));
388 int
389 api_unmap(SCR *sp, char *name)
391 EXCMD cmd;
392 size_t wlen;
393 CHAR_T *wp;
395 ex_cinit(sp, &cmd, C_UNMAP, 0, OOBLNO, OOBLNO, 0);
396 CHAR2INT(sp, name, strlen(name) + 1, wp, wlen);
397 argv_exp0(sp, &cmd, wp, wlen - 1);
398 return (cmd.cmd->fn(sp, &cmd));
402 * api_opts_get --
403 * Return a option value as a string, in allocated memory.
404 * If the option is of type boolean, boolvalue is (un)set
405 * according to the value; otherwise boolvalue is -1.
407 * PUBLIC: int api_opts_get __P((SCR *, CHAR_T *, char **, int *));
410 api_opts_get(SCR *sp, CHAR_T *name, char **value, int *boolvalue)
412 OPTLIST const *op;
413 int offset;
415 if ((op = opts_search(name)) == NULL) {
416 opts_nomatch(sp, name);
417 return (1);
420 offset = op - optlist;
421 if (boolvalue != NULL)
422 *boolvalue = -1;
423 switch (op->type) {
424 case OPT_0BOOL:
425 case OPT_1BOOL:
426 MALLOC_RET(sp, *value, char *, STRLEN(op->name) + 2 + 1);
427 (void)sprintf(*value,
428 "%s"WS, O_ISSET(sp, offset) ? "" : "no", op->name);
429 if (boolvalue != NULL)
430 *boolvalue = O_ISSET(sp, offset);
431 break;
432 case OPT_NUM:
433 MALLOC_RET(sp, *value, char *, 20);
434 (void)sprintf(*value, "%lu", (u_long)O_VAL(sp, offset));
435 break;
436 case OPT_STR:
437 if (O_STR(sp, offset) == NULL) {
438 MALLOC_RET(sp, *value, char *, 2);
439 value[0] = '\0';
440 } else {
441 MALLOC_RET(sp,
442 *value, char *, strlen(O_STR(sp, offset)) + 1);
443 (void)sprintf(*value, "%s", O_STR(sp, offset));
445 break;
447 return (0);
451 * api_opts_set --
452 * Set options.
454 * PUBLIC: int api_opts_set __P((SCR *, CHAR_T *, char *, u_long, int));
457 api_opts_set(SCR *sp, CHAR_T *name,
458 char *str_value, u_long num_value, int bool_value)
460 ARGS *ap[2], a, b;
461 OPTLIST const *op;
462 int rval;
463 size_t blen;
464 CHAR_T *bp;
466 if ((op = opts_search(name)) == NULL) {
467 opts_nomatch(sp, name);
468 return (1);
471 switch (op->type) {
472 case OPT_0BOOL:
473 case OPT_1BOOL:
474 GET_SPACE_RETW(sp, bp, blen, 64);
475 a.len = SPRINTF(bp, 64, L("%s"WS), bool_value ? "" : "no", name);
476 break;
477 case OPT_NUM:
478 GET_SPACE_RETW(sp, bp, blen, 64);
479 a.len = SPRINTF(bp, 64, L(""WS"=%lu"), name, num_value);
480 break;
481 case OPT_STR:
482 GET_SPACE_RETW(sp, bp, blen, 1024);
483 a.len = SPRINTF(bp, 1024, L(""WS"=%s"), name, str_value);
484 break;
485 default:
486 bp = NULL;
487 break;
490 a.bp = bp;
491 b.len = 0;
492 b.bp = NULL;
493 ap[0] = &a;
494 ap[1] = &b;
495 rval = opts_set(sp, ap, NULL);
497 FREE_SPACEW(sp, bp, blen);
499 return (rval);
503 * api_run_str --
504 * Execute a string as an ex command.
506 * PUBLIC: int api_run_str __P((SCR *, char *));
508 int
509 api_run_str(SCR *sp, char *cmd)
511 size_t wlen;
512 CHAR_T *wp;
514 CHAR2INT(sp, cmd, strlen(cmd)+1, wp, wlen);
515 return (ex_run_str(sp, NULL, wp, wlen - 1, 0, 0));
519 * PUBLIC: TAGQ * api_tagq_new __P((SCR*, char*));
521 TAGQ *
522 api_tagq_new(SCR *sp, char *tag)
524 TAGQ *tqp;
525 size_t len;
527 /* Allocate and initialize the tag queue structure. */
528 len = strlen(tag);
529 CALLOC_GOTO(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + len + 1);
530 CIRCLEQ_INIT(&tqp->tagq);
531 tqp->tag = tqp->buf;
532 memcpy(tqp->tag, tag, (tqp->tlen = len) + 1);
534 return tqp;
536 alloc_err:
537 return (NULL);
541 * PUBLIC: void api_tagq_add __P((SCR*, TAGQ*, char*, char *, char *));
543 void
544 api_tagq_add(SCR *sp, TAGQ *tqp, char *filename, char *search, char *msg)
546 TAG *tp;
547 CHAR_T *wp;
548 size_t wlen;
549 size_t flen = strlen(filename);
550 size_t slen = strlen(search);
551 size_t mlen = strlen(msg);
553 CALLOC_GOTO(sp, tp, TAG *, 1,
554 sizeof(TAG) - 1 + flen + 1 +
555 (slen + 1 + mlen + 1) * sizeof(CHAR_T));
556 tp->fname = (char *)tp->buf;
557 memcpy(tp->fname, filename, flen + 1);
558 tp->fnlen = flen;
559 tp->search = (CHAR_T *)((char *)tp->fname + flen + 1);
560 CHAR2INT(sp, search, slen + 1, wp, wlen);
561 MEMCPYW(tp->search, wp, wlen);
562 tp->slen = slen;
563 tp->msg = tp->search + slen + 1;
564 CHAR2INT(sp, msg, mlen + 1, wp, wlen);
565 MEMCPYW(tp->msg, wp, wlen);
566 tp->mlen = mlen;
567 CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q);
569 alloc_err:
570 return;
574 * PUBLIC: int api_tagq_push __P((SCR*, TAGQ**));
577 api_tagq_push(SCR *sp, TAGQ **tqpp)
579 TAGQ *tqp;
581 tqp = *tqpp;
583 *tqpp = 0;
585 /* Check to see if we found anything. */
586 if (tqp->tagq.cqh_first == (void *)&tqp->tagq) {
587 free(tqp);
588 return 0;
591 tqp->current = tqp->tagq.cqh_first;
593 if (tagq_push(sp, tqp, 0, 0))
594 return 1;
596 return (0);
600 * PUBLIC: void api_tagq_free __P((SCR*, TAGQ*));
602 void
603 api_tagq_free(SCR *sp, TAGQ *tqp)
605 if (tqp)
606 tagq_free(sp, tqp);