import libedit from OpenBSD
[unleashed.git] / lib / libedit / el.c
blob2b57de13e6e37df3ba00fd1bd17379c241ef6395
1 /* $OpenBSD: el.c,v 1.37 2017/04/12 18:24:37 tb Exp $ */
2 /* $NetBSD: el.c,v 1.61 2011/01/27 23:11:40 christos Exp $ */
4 /*-
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include "config.h"
39 * el.c: EditLine interface functions
41 #include <sys/types.h>
42 #include <ctype.h>
43 #include <langinfo.h>
44 #include <limits.h>
45 #include <locale.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <string.h>
50 #include "el.h"
51 #include "parse.h"
52 #include "read.h"
54 /* el_init():
55 * Initialize editline and set default parameters.
57 EditLine *
58 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
60 EditLine *el = (EditLine *) calloc(1, sizeof(EditLine));
62 if (el == NULL)
63 return NULL;
65 el->el_infile = fin;
66 el->el_outfile = fout;
67 el->el_errfile = ferr;
69 el->el_infd = fileno(fin);
70 el->el_outfd = fileno(fout);
71 el->el_errfd = fileno(ferr);
73 el->el_prog = wcsdup(ct_decode_string(prog, &el->el_scratch));
74 if (el->el_prog == NULL) {
75 free(el);
76 return NULL;
80 * Initialize all the modules. Order is important!!!
82 el->el_flags = 0;
83 if (setlocale(LC_CTYPE, NULL) != NULL){
84 if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
85 el->el_flags |= CHARSET_IS_UTF8;
88 if (terminal_init(el) == -1) {
89 free(el->el_prog);
90 free(el);
91 return NULL;
93 (void) keymacro_init(el);
94 (void) map_init(el);
95 if (tty_init(el) == -1)
96 el->el_flags |= NO_TTY;
97 (void) ch_init(el);
98 (void) search_init(el);
99 (void) hist_init(el);
100 (void) prompt_init(el);
101 (void) sig_init(el);
102 if (read_init(el) == -1) {
103 el_end(el);
104 return NULL;
106 return el;
110 /* el_end():
111 * Clean up.
113 void
114 el_end(EditLine *el)
117 if (el == NULL)
118 return;
120 el_reset(el);
122 terminal_end(el);
123 keymacro_end(el);
124 map_end(el);
125 tty_end(el);
126 ch_end(el);
127 read_end(el->el_read);
128 search_end(el);
129 hist_end(el);
130 prompt_end(el);
131 sig_end(el);
133 free(el->el_prog);
134 free(el->el_scratch.cbuff);
135 free(el->el_scratch.wbuff);
136 free(el->el_lgcyconv.cbuff);
137 free(el->el_lgcyconv.wbuff);
138 free(el);
142 /* el_reset():
143 * Reset the tty and the parser
145 void
146 el_reset(EditLine *el)
149 tty_cookedmode(el);
150 ch_reset(el); /* XXX: Do we want that? */
154 /* el_set():
155 * set the editline parameters
158 el_wset(EditLine *el, int op, ...)
160 va_list ap;
161 int rv = 0;
163 if (el == NULL)
164 return -1;
165 va_start(ap, op);
167 switch (op) {
168 case EL_PROMPT:
169 case EL_RPROMPT: {
170 el_pfunc_t p = va_arg(ap, el_pfunc_t);
172 rv = prompt_set(el, p, 0, op, 1);
173 break;
176 case EL_RESIZE: {
177 el_zfunc_t p = va_arg(ap, el_zfunc_t);
178 void *arg = va_arg(ap, void *);
179 rv = ch_resizefun(el, p, arg);
180 break;
183 case EL_PROMPT_ESC:
184 case EL_RPROMPT_ESC: {
185 el_pfunc_t p = va_arg(ap, el_pfunc_t);
186 int c = va_arg(ap, int);
188 rv = prompt_set(el, p, c, op, 1);
189 break;
192 case EL_TERMINAL:
193 rv = terminal_set(el, va_arg(ap, char *));
194 break;
196 case EL_EDITOR:
197 rv = map_set_editor(el, va_arg(ap, wchar_t *));
198 break;
200 case EL_SIGNAL:
201 if (va_arg(ap, int))
202 el->el_flags |= HANDLE_SIGNALS;
203 else
204 el->el_flags &= ~HANDLE_SIGNALS;
205 break;
207 case EL_BIND:
208 case EL_TELLTC:
209 case EL_SETTC:
210 case EL_ECHOTC:
211 case EL_SETTY:
213 const wchar_t *argv[20];
214 int i;
216 for (i = 1; i < 20; i++)
217 if ((argv[i] = va_arg(ap, wchar_t *)) == NULL)
218 break;
220 switch (op) {
221 case EL_BIND:
222 argv[0] = L"bind";
223 rv = map_bind(el, i, argv);
224 break;
226 case EL_TELLTC:
227 argv[0] = L"telltc";
228 rv = terminal_telltc(el, i, argv);
229 break;
231 case EL_SETTC:
232 argv[0] = L"settc";
233 rv = terminal_settc(el, i, argv);
234 break;
236 case EL_ECHOTC:
237 argv[0] = L"echotc";
238 rv = terminal_echotc(el, i, argv);
239 break;
241 case EL_SETTY:
242 argv[0] = L"setty";
243 rv = tty_stty(el, i, argv);
244 break;
246 default:
247 rv = -1;
248 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
249 break;
251 break;
254 case EL_ADDFN:
256 wchar_t *name = va_arg(ap, wchar_t *);
257 wchar_t *help = va_arg(ap, wchar_t *);
258 el_func_t func = va_arg(ap, el_func_t);
260 rv = map_addfunc(el, name, help, func);
261 break;
264 case EL_HIST:
266 hist_fun_t func = va_arg(ap, hist_fun_t);
267 void *ptr = va_arg(ap, void *);
269 rv = hist_set(el, func, ptr);
270 if (!(el->el_flags & CHARSET_IS_UTF8))
271 el->el_flags &= ~NARROW_HISTORY;
272 break;
275 case EL_EDITMODE:
276 if (va_arg(ap, int))
277 el->el_flags &= ~EDIT_DISABLED;
278 else
279 el->el_flags |= EDIT_DISABLED;
280 rv = 0;
281 break;
283 case EL_GETCFN:
285 el_rfunc_t rc = va_arg(ap, el_rfunc_t);
286 rv = el_read_setfn(el->el_read, rc);
287 break;
290 case EL_CLIENTDATA:
291 el->el_data = va_arg(ap, void *);
292 break;
294 case EL_UNBUFFERED:
295 rv = va_arg(ap, int);
296 if (rv && !(el->el_flags & UNBUFFERED)) {
297 el->el_flags |= UNBUFFERED;
298 read_prepare(el);
299 } else if (!rv && (el->el_flags & UNBUFFERED)) {
300 el->el_flags &= ~UNBUFFERED;
301 read_finish(el);
303 rv = 0;
304 break;
306 case EL_PREP_TERM:
307 rv = va_arg(ap, int);
308 if (rv)
309 (void) tty_rawmode(el);
310 else
311 (void) tty_cookedmode(el);
312 rv = 0;
313 break;
315 case EL_SETFP:
317 FILE *fp;
318 int what;
320 what = va_arg(ap, int);
321 fp = va_arg(ap, FILE *);
323 rv = 0;
324 switch (what) {
325 case 0:
326 el->el_infile = fp;
327 el->el_infd = fileno(fp);
328 break;
329 case 1:
330 el->el_outfile = fp;
331 el->el_outfd = fileno(fp);
332 break;
333 case 2:
334 el->el_errfile = fp;
335 el->el_errfd = fileno(fp);
336 break;
337 default:
338 rv = -1;
339 break;
341 break;
344 case EL_REFRESH:
345 re_clear_display(el);
346 re_refresh(el);
347 terminal__flush(el);
348 break;
350 default:
351 rv = -1;
352 break;
355 va_end(ap);
356 return rv;
360 /* el_get():
361 * retrieve the editline parameters
364 el_wget(EditLine *el, int op, ...)
366 va_list ap;
367 int rv;
369 if (el == NULL)
370 return -1;
372 va_start(ap, op);
374 switch (op) {
375 case EL_PROMPT:
376 case EL_RPROMPT: {
377 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
378 rv = prompt_get(el, p, 0, op);
379 break;
381 case EL_PROMPT_ESC:
382 case EL_RPROMPT_ESC: {
383 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
384 wchar_t *c = va_arg(ap, wchar_t *);
386 rv = prompt_get(el, p, c, op);
387 break;
390 case EL_EDITOR:
391 rv = map_get_editor(el, va_arg(ap, const wchar_t **));
392 break;
394 case EL_SIGNAL:
395 *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
396 rv = 0;
397 break;
399 case EL_EDITMODE:
400 *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
401 rv = 0;
402 break;
404 case EL_TERMINAL:
405 terminal_get(el, va_arg(ap, const char **));
406 rv = 0;
407 break;
409 case EL_GETTC:
411 static char name[] = "gettc";
412 char *argv[20];
413 int i;
415 for (i = 1; i < (int)(sizeof(argv) / sizeof(argv[0])); i++)
416 if ((argv[i] = va_arg(ap, char *)) == NULL)
417 break;
419 switch (op) {
420 case EL_GETTC:
421 argv[0] = name;
422 rv = terminal_gettc(el, i, argv);
423 break;
425 default:
426 rv = -1;
427 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
428 break;
430 break;
433 case EL_GETCFN:
434 *va_arg(ap, el_rfunc_t *) = el_read_getfn(el->el_read);
435 rv = 0;
436 break;
438 case EL_CLIENTDATA:
439 *va_arg(ap, void **) = el->el_data;
440 rv = 0;
441 break;
443 case EL_UNBUFFERED:
444 *va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED));
445 rv = 0;
446 break;
448 case EL_GETFP:
450 int what;
451 FILE **fpp;
453 what = va_arg(ap, int);
454 fpp = va_arg(ap, FILE **);
455 rv = 0;
456 switch (what) {
457 case 0:
458 *fpp = el->el_infile;
459 break;
460 case 1:
461 *fpp = el->el_outfile;
462 break;
463 case 2:
464 *fpp = el->el_errfile;
465 break;
466 default:
467 rv = -1;
468 break;
470 break;
472 default:
473 rv = -1;
474 break;
476 va_end(ap);
478 return rv;
482 /* el_line():
483 * Return editing info
485 const LineInfoW *
486 el_wline(EditLine *el)
489 return (const LineInfoW *)(void *)&el->el_line;
493 /* el_source():
494 * Source a file
497 el_source(EditLine *el, const char *fname)
499 FILE *fp;
500 size_t len;
501 ssize_t slen;
502 char *ptr;
503 #ifdef HAVE_ISSETUGID
504 char path[PATH_MAX];
505 #endif
506 const wchar_t *dptr;
508 fp = NULL;
509 if (fname == NULL) {
510 #ifdef HAVE_ISSETUGID
511 static const char elpath[] = "/.editrc";
513 if (issetugid())
514 return -1;
515 if ((ptr = getenv("HOME")) == NULL)
516 return -1;
517 if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
518 return -1;
519 if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
520 return -1;
521 fname = path;
522 #else
524 * If issetugid() is missing, always return an error, in order
525 * to keep from inadvertently opening up the user to a security
526 * hole.
528 return -1;
529 #endif
531 if (fp == NULL)
532 fp = fopen(fname, "r");
533 if (fp == NULL)
534 return -1;
536 ptr = NULL;
537 len = 0;
538 while ((slen = getline(&ptr, &len, fp)) != -1) {
539 if (*ptr == '\n')
540 continue; /* Empty line. */
541 if (slen > 0 && ptr[--slen] == '\n')
542 ptr[slen] = '\0';
544 dptr = ct_decode_string(ptr, &el->el_scratch);
545 if (!dptr)
546 continue;
547 /* loop until first non-space char or EOL */
548 while (*dptr != '\0' && iswspace(*dptr))
549 dptr++;
550 if (*dptr == '#')
551 continue; /* ignore, this is a comment line */
552 if (parse_line(el, dptr) == -1) {
553 free(ptr);
554 (void) fclose(fp);
555 return -1;
558 free(ptr);
559 (void) fclose(fp);
560 return 0;
564 /* el_resize():
565 * Called from program when terminal is resized
567 void
568 el_resize(EditLine *el)
570 int lins, cols;
571 sigset_t oset, nset;
573 (void) sigemptyset(&nset);
574 (void) sigaddset(&nset, SIGWINCH);
575 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
577 /* get the correct window size */
578 if (terminal_get_size(el, &lins, &cols))
579 terminal_change_size(el, lins, cols);
581 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
585 /* el_beep():
586 * Called from the program to beep
588 void
589 el_beep(EditLine *el)
592 terminal_beep(el);
596 /* el_editmode()
597 * Set the state of EDIT_DISABLED from the `edit' command.
599 protected int
600 /*ARGSUSED*/
601 el_editmode(EditLine *el, int argc, const wchar_t **argv)
603 const wchar_t *how;
605 if (argv == NULL || argc != 2 || argv[1] == NULL)
606 return -1;
608 how = argv[1];
609 if (wcscmp(how, L"on") == 0) {
610 el->el_flags &= ~EDIT_DISABLED;
611 tty_rawmode(el);
612 } else if (wcscmp(how, L"off") == 0) {
613 tty_cookedmode(el);
614 el->el_flags |= EDIT_DISABLED;
616 else {
617 (void) fprintf(el->el_errfile, "edit: Bad value `%ls'.\n",
618 how);
619 return -1;
621 return 0;