el.c revision 1.97 1 /* $NetBSD: el.c,v 1.97 2018/11/18 17:09:39 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94";
39 #else
40 __RCSID("$NetBSD: el.c,v 1.97 2018/11/18 17:09:39 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43
44 /*
45 * el.c: EditLine interface functions
46 */
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <ctype.h>
50 #include <langinfo.h>
51 #include <locale.h>
52 #include <stdarg.h>
53 #include <stdlib.h>
54 #include <string.h>
55
56 #include "el.h"
57 #include "parse.h"
58 #include "read.h"
59
60 /* el_init():
61 * Initialize editline and set default parameters.
62 */
63 EditLine *
64 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
65 {
66 return el_init_fd(prog, fin, fout, ferr, fileno(fin), fileno(fout),
67 fileno(ferr));
68 }
69
70 libedit_private EditLine *
71 el_init_internal(const char *prog, FILE *fin, FILE *fout, FILE *ferr,
72 int fdin, int fdout, int fderr, int flags)
73 {
74 EditLine *el = el_malloc(sizeof(*el));
75
76 if (el == NULL)
77 return NULL;
78
79 memset(el, 0, sizeof(EditLine));
80
81 el->el_infile = fin;
82 el->el_outfile = fout;
83 el->el_errfile = ferr;
84
85 el->el_infd = fdin;
86 el->el_outfd = fdout;
87 el->el_errfd = fderr;
88
89 el->el_prog = wcsdup(ct_decode_string(prog, &el->el_scratch));
90 if (el->el_prog == NULL) {
91 el_free(el);
92 return NULL;
93 }
94
95 /*
96 * Initialize all the modules. Order is important!!!
97 */
98 el->el_flags = flags;
99
100 if (terminal_init(el) == -1) {
101 el_free(el->el_prog);
102 el_free(el);
103 return NULL;
104 }
105 (void) keymacro_init(el);
106 (void) map_init(el);
107 if (tty_init(el) == -1)
108 el->el_flags |= NO_TTY;
109 (void) ch_init(el);
110 (void) search_init(el);
111 (void) hist_init(el);
112 (void) prompt_init(el);
113 (void) sig_init(el);
114 (void) literal_init(el);
115 if (read_init(el) == -1) {
116 el_end(el);
117 return NULL;
118 }
119 return el;
120 }
121
122 EditLine *
123 el_init_fd(const char *prog, FILE *fin, FILE *fout, FILE *ferr,
124 int fdin, int fdout, int fderr)
125 {
126 return el_init_internal(prog, fin, fout, ferr, fdin, fdout, fderr, 0);
127 }
128
129 /* el_end():
130 * Clean up.
131 */
132 void
133 el_end(EditLine *el)
134 {
135
136 if (el == NULL)
137 return;
138
139 el_reset(el);
140
141 terminal_end(el);
142 keymacro_end(el);
143 map_end(el);
144 if (!(el->el_flags & NO_TTY))
145 tty_end(el, TCSAFLUSH);
146 ch_end(el);
147 read_end(el->el_read);
148 search_end(el);
149 hist_end(el);
150 prompt_end(el);
151 sig_end(el);
152 literal_end(el);
153
154 el_free(el->el_prog);
155 el_free(el->el_visual.cbuff);
156 el_free(el->el_visual.wbuff);
157 el_free(el->el_scratch.cbuff);
158 el_free(el->el_scratch.wbuff);
159 el_free(el->el_lgcyconv.cbuff);
160 el_free(el->el_lgcyconv.wbuff);
161 el_free(el);
162 }
163
164
165 /* el_reset():
166 * Reset the tty and the parser
167 */
168 void
169 el_reset(EditLine *el)
170 {
171
172 tty_cookedmode(el);
173 ch_reset(el); /* XXX: Do we want that? */
174 }
175
176
177 /* el_set():
178 * set the editline parameters
179 */
180 int
181 el_wset(EditLine *el, int op, ...)
182 {
183 va_list ap;
184 int rv = 0;
185
186 if (el == NULL)
187 return -1;
188 va_start(ap, op);
189
190 switch (op) {
191 case EL_PROMPT:
192 case EL_RPROMPT: {
193 el_pfunc_t p = va_arg(ap, el_pfunc_t);
194
195 rv = prompt_set(el, p, 0, op, 1);
196 break;
197 }
198
199 case EL_RESIZE: {
200 el_zfunc_t p = va_arg(ap, el_zfunc_t);
201 void *arg = va_arg(ap, void *);
202 rv = ch_resizefun(el, p, arg);
203 break;
204 }
205
206 case EL_ALIAS_TEXT: {
207 el_afunc_t p = va_arg(ap, el_afunc_t);
208 void *arg = va_arg(ap, void *);
209 rv = ch_aliasfun(el, p, arg);
210 break;
211 }
212
213 case EL_PROMPT_ESC:
214 case EL_RPROMPT_ESC: {
215 el_pfunc_t p = va_arg(ap, el_pfunc_t);
216 int c = va_arg(ap, int);
217
218 rv = prompt_set(el, p, (wchar_t)c, op, 1);
219 break;
220 }
221
222 case EL_TERMINAL:
223 rv = terminal_set(el, va_arg(ap, char *));
224 break;
225
226 case EL_EDITOR:
227 rv = map_set_editor(el, va_arg(ap, wchar_t *));
228 break;
229
230 case EL_SIGNAL:
231 if (va_arg(ap, int))
232 el->el_flags |= HANDLE_SIGNALS;
233 else
234 el->el_flags &= ~HANDLE_SIGNALS;
235 break;
236
237 case EL_BIND:
238 case EL_TELLTC:
239 case EL_SETTC:
240 case EL_ECHOTC:
241 case EL_SETTY:
242 {
243 const wchar_t *argv[20];
244 int i;
245
246 for (i = 1; i < (int)__arraycount(argv); i++)
247 if ((argv[i] = va_arg(ap, wchar_t *)) == NULL)
248 break;
249
250 switch (op) {
251 case EL_BIND:
252 argv[0] = L"bind";
253 rv = map_bind(el, i, argv);
254 break;
255
256 case EL_TELLTC:
257 argv[0] = L"telltc";
258 rv = terminal_telltc(el, i, argv);
259 break;
260
261 case EL_SETTC:
262 argv[0] = L"settc";
263 rv = terminal_settc(el, i, argv);
264 break;
265
266 case EL_ECHOTC:
267 argv[0] = L"echotc";
268 rv = terminal_echotc(el, i, argv);
269 break;
270
271 case EL_SETTY:
272 argv[0] = L"setty";
273 rv = tty_stty(el, i, argv);
274 break;
275
276 default:
277 rv = -1;
278 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
279 break;
280 }
281 break;
282 }
283
284 case EL_ADDFN:
285 {
286 wchar_t *name = va_arg(ap, wchar_t *);
287 wchar_t *help = va_arg(ap, wchar_t *);
288 el_func_t func = va_arg(ap, el_func_t);
289
290 rv = map_addfunc(el, name, help, func);
291 break;
292 }
293
294 case EL_HIST:
295 {
296 hist_fun_t func = va_arg(ap, hist_fun_t);
297 void *ptr = va_arg(ap, void *);
298
299 rv = hist_set(el, func, ptr);
300 if (MB_CUR_MAX == 1)
301 el->el_flags &= ~NARROW_HISTORY;
302 break;
303 }
304
305 case EL_EDITMODE:
306 if (va_arg(ap, int))
307 el->el_flags &= ~EDIT_DISABLED;
308 else
309 el->el_flags |= EDIT_DISABLED;
310 rv = 0;
311 break;
312
313 case EL_GETCFN:
314 {
315 el_rfunc_t rc = va_arg(ap, el_rfunc_t);
316 rv = el_read_setfn(el->el_read, rc);
317 break;
318 }
319
320 case EL_CLIENTDATA:
321 el->el_data = va_arg(ap, void *);
322 break;
323
324 case EL_UNBUFFERED:
325 rv = va_arg(ap, int);
326 if (rv && !(el->el_flags & UNBUFFERED)) {
327 el->el_flags |= UNBUFFERED;
328 read_prepare(el);
329 } else if (!rv && (el->el_flags & UNBUFFERED)) {
330 el->el_flags &= ~UNBUFFERED;
331 read_finish(el);
332 }
333 rv = 0;
334 break;
335
336 case EL_PREP_TERM:
337 rv = va_arg(ap, int);
338 if (rv)
339 (void) tty_rawmode(el);
340 else
341 (void) tty_cookedmode(el);
342 rv = 0;
343 break;
344
345 case EL_SETFP:
346 {
347 FILE *fp;
348 int what;
349
350 what = va_arg(ap, int);
351 fp = va_arg(ap, FILE *);
352
353 rv = 0;
354 switch (what) {
355 case 0:
356 el->el_infile = fp;
357 el->el_infd = fileno(fp);
358 break;
359 case 1:
360 el->el_outfile = fp;
361 el->el_outfd = fileno(fp);
362 break;
363 case 2:
364 el->el_errfile = fp;
365 el->el_errfd = fileno(fp);
366 break;
367 default:
368 rv = -1;
369 break;
370 }
371 break;
372 }
373
374 case EL_REFRESH:
375 re_clear_display(el);
376 re_refresh(el);
377 terminal__flush(el);
378 break;
379
380 default:
381 rv = -1;
382 break;
383 }
384
385 va_end(ap);
386 return rv;
387 }
388
389
390 /* el_get():
391 * retrieve the editline parameters
392 */
393 int
394 el_wget(EditLine *el, int op, ...)
395 {
396 va_list ap;
397 int rv;
398
399 if (el == NULL)
400 return -1;
401
402 va_start(ap, op);
403
404 switch (op) {
405 case EL_PROMPT:
406 case EL_RPROMPT: {
407 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
408 rv = prompt_get(el, p, 0, op);
409 break;
410 }
411 case EL_PROMPT_ESC:
412 case EL_RPROMPT_ESC: {
413 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
414 wchar_t *c = va_arg(ap, wchar_t *);
415
416 rv = prompt_get(el, p, c, op);
417 break;
418 }
419
420 case EL_EDITOR:
421 rv = map_get_editor(el, va_arg(ap, const wchar_t **));
422 break;
423
424 case EL_SIGNAL:
425 *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
426 rv = 0;
427 break;
428
429 case EL_EDITMODE:
430 *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
431 rv = 0;
432 break;
433
434 case EL_TERMINAL:
435 terminal_get(el, va_arg(ap, const char **));
436 rv = 0;
437 break;
438
439 case EL_GETTC:
440 {
441 static char name[] = "gettc";
442 char *argv[20];
443 int i;
444
445 for (i = 1; i < (int)__arraycount(argv); i++)
446 if ((argv[i] = va_arg(ap, char *)) == NULL)
447 break;
448
449 argv[0] = name;
450 rv = terminal_gettc(el, i, argv);
451 break;
452 }
453
454 case EL_GETCFN:
455 *va_arg(ap, el_rfunc_t *) = el_read_getfn(el->el_read);
456 rv = 0;
457 break;
458
459 case EL_CLIENTDATA:
460 *va_arg(ap, void **) = el->el_data;
461 rv = 0;
462 break;
463
464 case EL_UNBUFFERED:
465 *va_arg(ap, int *) = (el->el_flags & UNBUFFERED) != 0;
466 rv = 0;
467 break;
468
469 case EL_GETFP:
470 {
471 int what;
472 FILE **fpp;
473
474 what = va_arg(ap, int);
475 fpp = va_arg(ap, FILE **);
476 rv = 0;
477 switch (what) {
478 case 0:
479 *fpp = el->el_infile;
480 break;
481 case 1:
482 *fpp = el->el_outfile;
483 break;
484 case 2:
485 *fpp = el->el_errfile;
486 break;
487 default:
488 rv = -1;
489 break;
490 }
491 break;
492 }
493 default:
494 rv = -1;
495 break;
496 }
497 va_end(ap);
498
499 return rv;
500 }
501
502
503 /* el_line():
504 * Return editing info
505 */
506 const LineInfoW *
507 el_wline(EditLine *el)
508 {
509
510 return (const LineInfoW *)(void *)&el->el_line;
511 }
512
513
514 /* el_source():
515 * Source a file
516 */
517 int
518 el_source(EditLine *el, const char *fname)
519 {
520 FILE *fp;
521 size_t len;
522 ssize_t slen;
523 char *ptr;
524 char *path = NULL;
525 const wchar_t *dptr;
526 int error = 0;
527
528 fp = NULL;
529 if (fname == NULL) {
530 #ifdef HAVE_ISSETUGID
531 if (issetugid())
532 return -1;
533
534 if ((fname = getenv("EDITRC")) == NULL) {
535 static const char elpath[] = "/.editrc";
536 size_t plen = sizeof(elpath);
537
538 if ((ptr = getenv("HOME")) == NULL)
539 return -1;
540 plen += strlen(ptr);
541 if ((path = el_malloc(plen * sizeof(*path))) == NULL)
542 return -1;
543 (void)snprintf(path, plen, "%s%s", ptr,
544 elpath + (*ptr == '\0'));
545 fname = path;
546 }
547 #else
548 /*
549 * If issetugid() is missing, always return an error, in order
550 * to keep from inadvertently opening up the user to a security
551 * hole.
552 */
553 return -1;
554 #endif
555 }
556 if (fname[0] == '\0')
557 return -1;
558
559 if (fp == NULL)
560 fp = fopen(fname, "r");
561 if (fp == NULL) {
562 el_free(path);
563 return -1;
564 }
565
566 ptr = NULL;
567 len = 0;
568 while ((slen = getline(&ptr, &len, fp)) != -1) {
569 if (*ptr == '\n')
570 continue; /* Empty line. */
571 if (slen > 0 && ptr[--slen] == '\n')
572 ptr[slen] = '\0';
573
574 dptr = ct_decode_string(ptr, &el->el_scratch);
575 if (!dptr)
576 continue;
577 /* loop until first non-space char or EOL */
578 while (*dptr != '\0' && iswspace(*dptr))
579 dptr++;
580 if (*dptr == '#')
581 continue; /* ignore, this is a comment line */
582 if ((error = parse_line(el, dptr)) == -1)
583 break;
584 }
585 free(ptr);
586
587 el_free(path);
588 (void) fclose(fp);
589 return error;
590 }
591
592
593 /* el_resize():
594 * Called from program when terminal is resized
595 */
596 void
597 el_resize(EditLine *el)
598 {
599 int lins, cols;
600 sigset_t oset, nset;
601
602 (void) sigemptyset(&nset);
603 (void) sigaddset(&nset, SIGWINCH);
604 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
605
606 /* get the correct window size */
607 if (terminal_get_size(el, &lins, &cols))
608 terminal_change_size(el, lins, cols);
609
610 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
611 }
612
613
614 /* el_beep():
615 * Called from the program to beep
616 */
617 void
618 el_beep(EditLine *el)
619 {
620
621 terminal_beep(el);
622 }
623
624
625 /* el_editmode()
626 * Set the state of EDIT_DISABLED from the `edit' command.
627 */
628 libedit_private int
629 /*ARGSUSED*/
630 el_editmode(EditLine *el, int argc, const wchar_t **argv)
631 {
632 const wchar_t *how;
633
634 if (argv == NULL || argc != 2 || argv[1] == NULL)
635 return -1;
636
637 how = argv[1];
638 if (wcscmp(how, L"on") == 0) {
639 el->el_flags &= ~EDIT_DISABLED;
640 tty_rawmode(el);
641 } else if (wcscmp(how, L"off") == 0) {
642 tty_cookedmode(el);
643 el->el_flags |= EDIT_DISABLED;
644 }
645 else {
646 (void) fprintf(el->el_errfile, "edit: Bad value `%ls'.\n",
647 how);
648 return -1;
649 }
650 return 0;
651 }
652