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.
8 *
9 * See the LICENSE file for redistribution information.
10 */
11
12 #include "config.h"
13
14 #ifndef lint
15 static const char sccsid[] = "@(#)api.c 8.26 (Berkeley) 10/14/96";
16 #endif /* not lint */
17
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/time.h>
21
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>
29
30 #include "../common/common.h"
31
32 extern GS *__global_list; /* XXX */
33
34 /*
35 * api_fscreen --
36 * Return a pointer to the screen specified by the screen id
37 * or a file name.
38 *
39 * PUBLIC: SCR *api_fscreen __P((int, char *));
40 */
41 SCR *
api_fscreen(id,name)42 api_fscreen(id, name)
43 int id;
44 char *name;
45 {
46 GS *gp;
47 SCR *tsp;
48
49 gp = __global_list;
50
51 /* Search the displayed list. */
52 for (tsp = gp->dq.cqh_first;
53 tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
54 if (name == NULL) {
55 if (id == tsp->id)
56 return (tsp);
57 } else if (!strcmp(name, tsp->frp->name))
58 return (tsp);
59
60 /* Search the hidden list. */
61 for (tsp = gp->hq.cqh_first;
62 tsp != (void *)&gp->hq; tsp = tsp->q.cqe_next)
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 *, recno_t, char *, size_t));
76 */
77 int
api_aline(sp,lno,line,len)78 api_aline(sp, lno, line, len)
79 SCR *sp;
80 recno_t lno;
81 char *line;
82 size_t len;
83 {
84 return (db_append(sp, 1, lno, line, len));
85 }
86
87 /*
88 * api_dline --
89 * Delete a line.
90 *
91 * PUBLIC: int api_dline __P((SCR *, recno_t));
92 */
93 int
api_dline(sp,lno)94 api_dline(sp, lno)
95 SCR *sp;
96 recno_t lno;
97 {
98 return (db_delete(sp, lno));
99 }
100
101 /*
102 * api_gline --
103 * Get a line.
104 *
105 * PUBLIC: int api_gline __P((SCR *, recno_t, char **, size_t *));
106 */
107 int
api_gline(sp,lno,linepp,lenp)108 api_gline(sp, lno, linepp, lenp)
109 SCR *sp;
110 recno_t lno;
111 char **linepp;
112 size_t *lenp;
113 {
114 int isempty;
115
116 if (db_eget(sp, lno, linepp, lenp, &isempty)) {
117 if (isempty)
118 msgq(sp, M_ERR, "209|The file is empty");
119 return (1);
120 }
121 return (0);
122 }
123
124 /*
125 * api_iline --
126 * Insert a line.
127 *
128 * PUBLIC: int api_iline __P((SCR *, recno_t, char *, size_t));
129 */
130 int
api_iline(sp,lno,line,len)131 api_iline(sp, lno, line, len)
132 SCR *sp;
133 recno_t lno;
134 char *line;
135 size_t len;
136 {
137 return (db_insert(sp, lno, line, len));
138 }
139
140 /*
141 * api_lline --
142 * Return the line number of the last line in the file.
143 *
144 * PUBLIC: int api_lline __P((SCR *, recno_t *));
145 */
146 int
api_lline(sp,lnop)147 api_lline(sp, lnop)
148 SCR *sp;
149 recno_t *lnop;
150 {
151 return (db_last(sp, lnop));
152 }
153
154 /*
155 * api_sline --
156 * Set a line.
157 *
158 * PUBLIC: int api_sline __P((SCR *, recno_t, char *, size_t));
159 */
160 int
api_sline(sp,lno,line,len)161 api_sline(sp, lno, line, len)
162 SCR *sp;
163 recno_t lno;
164 char *line;
165 size_t len;
166 {
167 return (db_set(sp, lno, line, len));
168 }
169
170 /*
171 * api_getmark --
172 * Get the mark.
173 *
174 * PUBLIC: int api_getmark __P((SCR *, int, MARK *));
175 */
176 int
api_getmark(sp,markname,mp)177 api_getmark(sp, markname, mp)
178 SCR *sp;
179 int markname;
180 MARK *mp;
181 {
182 return (mark_get(sp, (ARG_CHAR_T)markname, mp, M_ERR));
183 }
184
185 /*
186 * api_setmark --
187 * Set the mark.
188 *
189 * PUBLIC: int api_setmark __P((SCR *, int, MARK *));
190 */
191 int
api_setmark(sp,markname,mp)192 api_setmark(sp, markname, mp)
193 SCR *sp;
194 int markname;
195 MARK *mp;
196 {
197 return (mark_set(sp, (ARG_CHAR_T)markname, mp, 1));
198 }
199
200 /*
201 * api_nextmark --
202 * Return the first mark if next not set, otherwise return the
203 * subsequent mark.
204 *
205 * PUBLIC: int api_nextmark __P((SCR *, int, char *));
206 */
207 int
api_nextmark(sp,next,namep)208 api_nextmark(sp, next, namep)
209 SCR *sp;
210 int next;
211 char *namep;
212 {
213 LMARK *mp;
214
215 mp = sp->ep->marks.lh_first;
216 if (next)
217 for (; mp != NULL; mp = mp->q.le_next)
218 if (mp->name == *namep) {
219 mp = mp->q.le_next;
220 break;
221 }
222 if (mp == NULL)
223 return (1);
224 *namep = mp->name;
225 return (0);
226 }
227
228 /*
229 * api_getcursor --
230 * Get the cursor.
231 *
232 * PUBLIC: int api_getcursor __P((SCR *, MARK *));
233 */
234 int
api_getcursor(sp,mp)235 api_getcursor(sp, mp)
236 SCR *sp;
237 MARK *mp;
238 {
239 mp->lno = sp->lno;
240 mp->cno = sp->cno;
241 return (0);
242 }
243
244 /*
245 * api_setcursor --
246 * Set the cursor.
247 *
248 * PUBLIC: int api_setcursor __P((SCR *, MARK *));
249 */
250 int
api_setcursor(sp,mp)251 api_setcursor(sp, mp)
252 SCR *sp;
253 MARK *mp;
254 {
255 size_t len;
256
257 if (db_get(sp, mp->lno, DBG_FATAL, NULL, &len))
258 return (1);
259 if (mp->cno < 0 || mp->cno > len) {
260 msgq(sp, M_ERR, "Cursor set to nonexistent column");
261 return (1);
262 }
263
264 /* Set the cursor. */
265 sp->lno = mp->lno;
266 sp->cno = mp->cno;
267 return (0);
268 }
269
270 /*
271 * api_emessage --
272 * Print an error message.
273 *
274 * PUBLIC: void api_emessage __P((SCR *, char *));
275 */
276 void
api_emessage(sp,text)277 api_emessage(sp, text)
278 SCR *sp;
279 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(sp,text)291 api_imessage(sp, text)
292 SCR *sp;
293 char *text;
294 {
295 msgq(sp, M_INFO, "%s", text);
296 }
297
298 /*
299 * api_edit
300 * Create a new screen and return its id
301 * or edit a new file in the current screen.
302 *
303 * PUBLIC: int api_edit __P((SCR *, char *, SCR **, int));
304 */
305 int
api_edit(sp,file,spp,newscreen)306 api_edit(sp, file, spp, newscreen)
307 SCR *sp;
308 char *file;
309 SCR **spp;
310 int newscreen;
311 {
312 ARGS *ap[2], a;
313 EXCMD cmd;
314
315 if (file) {
316 ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, ap);
317 ex_cadd(&cmd, &a, file, strlen(file));
318 } else
319 ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, NULL);
320 if (newscreen)
321 cmd.flags |= E_NEWSCREEN; /* XXX */
322 if (cmd.cmd->fn(sp, &cmd))
323 return (1);
324 *spp = sp->nextdisp;
325 return (0);
326 }
327
328 /*
329 * api_escreen
330 * End a screen.
331 *
332 * PUBLIC: int api_escreen __P((SCR *));
333 */
334 int
api_escreen(sp)335 api_escreen(sp)
336 SCR *sp;
337 {
338 EXCMD cmd;
339
340 /*
341 * XXX
342 * If the interpreter exits anything other than the current
343 * screen, vi isn't going to update everything correctly.
344 */
345 ex_cinit(&cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0, NULL);
346 return (cmd.cmd->fn(sp, &cmd));
347 }
348
349 /*
350 * api_swscreen --
351 * Switch to a new screen.
352 *
353 * PUBLIC: int api_swscreen __P((SCR *, SCR *));
354 */
355 int
api_swscreen(sp,new)356 api_swscreen(sp, new)
357 SCR *sp, *new;
358 {
359 /*
360 * XXX
361 * If the interpreter switches from anything other than the
362 * current screen, vi isn't going to update everything correctly.
363 */
364 sp->nextdisp = new;
365 F_SET(sp, SC_SSWITCH);
366
367 return (0);
368 }
369
370 /*
371 * api_map --
372 * Map a key.
373 *
374 * PUBLIC: int api_map __P((SCR *, char *, char *, size_t));
375 */
376 int
api_map(sp,name,map,len)377 api_map(sp, name, map, len)
378 SCR *sp;
379 char *name, *map;
380 size_t len;
381 {
382 ARGS *ap[3], a, b;
383 EXCMD cmd;
384
385 ex_cinit(&cmd, C_MAP, 0, OOBLNO, OOBLNO, 0, ap);
386 ex_cadd(&cmd, &a, name, strlen(name));
387 ex_cadd(&cmd, &b, map, len);
388 return (cmd.cmd->fn(sp, &cmd));
389 }
390
391 /*
392 * api_unmap --
393 * Unmap a key.
394 *
395 * PUBLIC: int api_unmap __P((SCR *, char *));
396 */
397 int
api_unmap(sp,name)398 api_unmap(sp, name)
399 SCR *sp;
400 char *name;
401 {
402 ARGS *ap[2], a;
403 EXCMD cmd;
404
405 ex_cinit(&cmd, C_UNMAP, 0, OOBLNO, OOBLNO, 0, ap);
406 ex_cadd(&cmd, &a, name, strlen(name));
407 return (cmd.cmd->fn(sp, &cmd));
408 }
409
410 /*
411 * api_opts_get --
412 * Return a option value as a string, in allocated memory.
413 * If the option is of type boolean, boolvalue is (un)set
414 * according to the value; otherwise boolvalue is -1.
415 *
416 * PUBLIC: int api_opts_get __P((SCR *, char *, char **, int *));
417 */
418 int
api_opts_get(sp,name,value,boolvalue)419 api_opts_get(sp, name, value, boolvalue)
420 SCR *sp;
421 char *name, **value;
422 int *boolvalue;
423 {
424 OPTLIST const *op;
425 int offset;
426
427 if ((op = opts_search(name)) == NULL) {
428 opts_nomatch(sp, name);
429 return (1);
430 }
431
432 offset = op - optlist;
433 if (boolvalue != NULL)
434 *boolvalue = -1;
435 switch (op->type) {
436 case OPT_0BOOL:
437 case OPT_1BOOL:
438 MALLOC_RET(sp, *value, char *, strlen(op->name) + 2 + 1);
439 (void)sprintf(*value,
440 "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name);
441 if (boolvalue != NULL)
442 *boolvalue = O_ISSET(sp, offset);
443 break;
444 case OPT_NUM:
445 MALLOC_RET(sp, *value, char *, 20);
446 (void)sprintf(*value, "%lu", (u_long)O_VAL(sp, offset));
447 break;
448 case OPT_STR:
449 if (O_STR(sp, offset) == NULL) {
450 MALLOC_RET(sp, *value, char *, 2);
451 value[0] = '\0';
452 } else {
453 MALLOC_RET(sp,
454 *value, char *, strlen(O_STR(sp, offset)) + 1);
455 (void)sprintf(*value, "%s", O_STR(sp, offset));
456 }
457 break;
458 }
459 return (0);
460 }
461
462 /*
463 * api_opts_set --
464 * Set options.
465 *
466 * PUBLIC: int api_opts_set __P((SCR *, char *, char *, u_long, int));
467 */
468 int
api_opts_set(sp,name,str_value,num_value,bool_value)469 api_opts_set(sp, name, str_value, num_value, bool_value)
470 SCR *sp;
471 char *name, *str_value;
472 u_long num_value;
473 int bool_value;
474 {
475 ARGS *ap[2], a, b;
476 OPTLIST const *op;
477 int rval;
478 size_t blen;
479 char *bp;
480
481 if ((op = opts_search(name)) == NULL) {
482 opts_nomatch(sp, name);
483 return (1);
484 }
485
486 switch (op->type) {
487 case OPT_0BOOL:
488 case OPT_1BOOL:
489 GET_SPACE_RET(sp, bp, blen, 64);
490 a.len = snprintf(bp, 64, "%s%s", bool_value ? "" : "no", name);
491 break;
492 case OPT_NUM:
493 GET_SPACE_RET(sp, bp, blen, 64);
494 a.len = snprintf(bp, 64, "%s=%lu", name, num_value);
495 break;
496 case OPT_STR:
497 GET_SPACE_RET(sp, bp, blen, 1024);
498 a.len = snprintf(bp, 1024, "%s=%s", name, str_value);
499 break;
500 }
501 a.bp = bp;
502 b.len = 0;
503 b.bp = NULL;
504 ap[0] = &a;
505 ap[1] = &b;
506 rval = opts_set(sp, ap, NULL);
507
508 FREE_SPACE(sp, bp, blen);
509
510 return (rval);
511 }
512
513 /*
514 * api_run_str --
515 * Execute a string as an ex command.
516 *
517 * PUBLIC: int api_run_str __P((SCR *, char *));
518 */
519 int
api_run_str(sp,cmd)520 api_run_str(sp, cmd)
521 SCR *sp;
522 char *cmd;
523 {
524 return (ex_run_str(sp, NULL, cmd, strlen(cmd), 0, 0));
525 }
526