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