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 $ */
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
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
39 * el.c: EditLine interface functions
41 #include <sys/types.h>
55 * Initialize editline and set default parameters.
58 el_init(const char *prog
, FILE *fin
, FILE *fout
, FILE *ferr
)
60 EditLine
*el
= (EditLine
*) calloc(1, sizeof(EditLine
));
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
) {
80 * Initialize all the modules. Order is important!!!
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) {
93 (void) keymacro_init(el
);
95 if (tty_init(el
) == -1)
96 el
->el_flags
|= NO_TTY
;
98 (void) search_init(el
);
100 (void) prompt_init(el
);
102 if (read_init(el
) == -1) {
127 read_end(el
->el_read
);
134 free(el
->el_scratch
.cbuff
);
135 free(el
->el_scratch
.wbuff
);
136 free(el
->el_lgcyconv
.cbuff
);
137 free(el
->el_lgcyconv
.wbuff
);
143 * Reset the tty and the parser
146 el_reset(EditLine
*el
)
150 ch_reset(el
); /* XXX: Do we want that? */
155 * set the editline parameters
158 el_wset(EditLine
*el
, int op
, ...)
170 el_pfunc_t p
= va_arg(ap
, el_pfunc_t
);
172 rv
= prompt_set(el
, p
, 0, op
, 1);
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
);
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);
193 rv
= terminal_set(el
, va_arg(ap
, char *));
197 rv
= map_set_editor(el
, va_arg(ap
, wchar_t *));
202 el
->el_flags
|= HANDLE_SIGNALS
;
204 el
->el_flags
&= ~HANDLE_SIGNALS
;
213 const wchar_t *argv
[20];
216 for (i
= 1; i
< 20; i
++)
217 if ((argv
[i
] = va_arg(ap
, wchar_t *)) == NULL
)
223 rv
= map_bind(el
, i
, argv
);
228 rv
= terminal_telltc(el
, i
, argv
);
233 rv
= terminal_settc(el
, i
, argv
);
238 rv
= terminal_echotc(el
, i
, argv
);
243 rv
= tty_stty(el
, i
, argv
);
248 EL_ABORT((el
->el_errfile
, "Bad op %d\n", op
));
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
);
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
;
277 el
->el_flags
&= ~EDIT_DISABLED
;
279 el
->el_flags
|= EDIT_DISABLED
;
285 el_rfunc_t rc
= va_arg(ap
, el_rfunc_t
);
286 rv
= el_read_setfn(el
->el_read
, rc
);
291 el
->el_data
= va_arg(ap
, void *);
295 rv
= va_arg(ap
, int);
296 if (rv
&& !(el
->el_flags
& UNBUFFERED
)) {
297 el
->el_flags
|= UNBUFFERED
;
299 } else if (!rv
&& (el
->el_flags
& UNBUFFERED
)) {
300 el
->el_flags
&= ~UNBUFFERED
;
307 rv
= va_arg(ap
, int);
309 (void) tty_rawmode(el
);
311 (void) tty_cookedmode(el
);
320 what
= va_arg(ap
, int);
321 fp
= va_arg(ap
, FILE *);
327 el
->el_infd
= fileno(fp
);
331 el
->el_outfd
= fileno(fp
);
335 el
->el_errfd
= fileno(fp
);
345 re_clear_display(el
);
361 * retrieve the editline parameters
364 el_wget(EditLine
*el
, int op
, ...)
377 el_pfunc_t
*p
= va_arg(ap
, el_pfunc_t
*);
378 rv
= prompt_get(el
, p
, 0, op
);
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
);
391 rv
= map_get_editor(el
, va_arg(ap
, const wchar_t **));
395 *va_arg(ap
, int *) = (el
->el_flags
& HANDLE_SIGNALS
);
400 *va_arg(ap
, int *) = !(el
->el_flags
& EDIT_DISABLED
);
405 terminal_get(el
, va_arg(ap
, const char **));
411 static char name
[] = "gettc";
415 for (i
= 1; i
< (int)(sizeof(argv
) / sizeof(argv
[0])); i
++)
416 if ((argv
[i
] = va_arg(ap
, char *)) == NULL
)
422 rv
= terminal_gettc(el
, i
, argv
);
427 EL_ABORT((el
->el_errfile
, "Bad op %d\n", op
));
434 *va_arg(ap
, el_rfunc_t
*) = el_read_getfn(el
->el_read
);
439 *va_arg(ap
, void **) = el
->el_data
;
444 *va_arg(ap
, int *) = (!(el
->el_flags
& UNBUFFERED
));
453 what
= va_arg(ap
, int);
454 fpp
= va_arg(ap
, FILE **);
458 *fpp
= el
->el_infile
;
461 *fpp
= el
->el_outfile
;
464 *fpp
= el
->el_errfile
;
483 * Return editing info
486 el_wline(EditLine
*el
)
489 return (const LineInfoW
*)(void *)&el
->el_line
;
497 el_source(EditLine
*el
, const char *fname
)
503 #ifdef HAVE_ISSETUGID
510 #ifdef HAVE_ISSETUGID
511 static const char elpath
[] = "/.editrc";
515 if ((ptr
= getenv("HOME")) == NULL
)
517 if (strlcpy(path
, ptr
, sizeof(path
)) >= sizeof(path
))
519 if (strlcat(path
, elpath
, sizeof(path
)) >= sizeof(path
))
524 * If issetugid() is missing, always return an error, in order
525 * to keep from inadvertently opening up the user to a security
532 fp
= fopen(fname
, "r");
538 while ((slen
= getline(&ptr
, &len
, fp
)) != -1) {
540 continue; /* Empty line. */
541 if (slen
> 0 && ptr
[--slen
] == '\n')
544 dptr
= ct_decode_string(ptr
, &el
->el_scratch
);
547 /* loop until first non-space char or EOL */
548 while (*dptr
!= '\0' && iswspace(*dptr
))
551 continue; /* ignore, this is a comment line */
552 if (parse_line(el
, dptr
) == -1) {
565 * Called from program when terminal is resized
568 el_resize(EditLine
*el
)
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
);
586 * Called from the program to beep
589 el_beep(EditLine
*el
)
597 * Set the state of EDIT_DISABLED from the `edit' command.
601 el_editmode(EditLine
*el
, int argc
, const wchar_t **argv
)
605 if (argv
== NULL
|| argc
!= 2 || argv
[1] == NULL
)
609 if (wcscmp(how
, L
"on") == 0) {
610 el
->el_flags
&= ~EDIT_DISABLED
;
612 } else if (wcscmp(how
, L
"off") == 0) {
614 el
->el_flags
|= EDIT_DISABLED
;
617 (void) fprintf(el
->el_errfile
, "edit: Bad value `%ls'.\n",