el.c revision 1.98 1 /* $NetBSD: el.c,v 1.98 2019/04/26 16:56:57 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.98 2019/04/26 16:56:57 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[3];
443 argv[0] = name;
444 argv[1] = va_arg(ap, char *);
445 argv[2] = va_arg(ap, void *);
446 rv = terminal_gettc(el, 3, argv);
447 break;
448 }
449
450 case EL_GETCFN:
451 *va_arg(ap, el_rfunc_t *) = el_read_getfn(el->el_read);
452 rv = 0;
453 break;
454
455 case EL_CLIENTDATA:
456 *va_arg(ap, void **) = el->el_data;
457 rv = 0;
458 break;
459
460 case EL_UNBUFFERED:
461 *va_arg(ap, int *) = (el->el_flags & UNBUFFERED) != 0;
462 rv = 0;
463 break;
464
465 case EL_GETFP:
466 {
467 int what;
468 FILE **fpp;
469
470 what = va_arg(ap, int);
471 fpp = va_arg(ap, FILE **);
472 rv = 0;
473 switch (what) {
474 case 0:
475 *fpp = el->el_infile;
476 break;
477 case 1:
478 *fpp = el->el_outfile;
479 break;
480 case 2:
481 *fpp = el->el_errfile;
482 break;
483 default:
484 rv = -1;
485 break;
486 }
487 break;
488 }
489 default:
490 rv = -1;
491 break;
492 }
493 va_end(ap);
494
495 return rv;
496 }
497
498
499 /* el_line():
500 * Return editing info
501 */
502 const LineInfoW *
503 el_wline(EditLine *el)
504 {
505
506 return (const LineInfoW *)(void *)&el->el_line;
507 }
508
509
510 /* el_source():
511 * Source a file
512 */
513 int
514 el_source(EditLine *el, const char *fname)
515 {
516 FILE *fp;
517 size_t len;
518 ssize_t slen;
519 char *ptr;
520 char *path = NULL;
521 const wchar_t *dptr;
522 int error = 0;
523
524 fp = NULL;
525 if (fname == NULL) {
526 #ifdef HAVE_ISSETUGID
527 if (issetugid())
528 return -1;
529
530 if ((fname = getenv("EDITRC")) == NULL) {
531 static const char elpath[] = "/.editrc";
532 size_t plen = sizeof(elpath);
533
534 if ((ptr = getenv("HOME")) == NULL)
535 return -1;
536 plen += strlen(ptr);
537 if ((path = el_malloc(plen * sizeof(*path))) == NULL)
538 return -1;
539 (void)snprintf(path, plen, "%s%s", ptr,
540 elpath + (*ptr == '\0'));
541 fname = path;
542 }
543 #else
544 /*
545 * If issetugid() is missing, always return an error, in order
546 * to keep from inadvertently opening up the user to a security
547 * hole.
548 */
549 return -1;
550 #endif
551 }
552 if (fname[0] == '\0')
553 return -1;
554
555 if (fp == NULL)
556 fp = fopen(fname, "r");
557 if (fp == NULL) {
558 el_free(path);
559 return -1;
560 }
561
562 ptr = NULL;
563 len = 0;
564 while ((slen = getline(&ptr, &len, fp)) != -1) {
565 if (*ptr == '\n')
566 continue; /* Empty line. */
567 if (slen > 0 && ptr[--slen] == '\n')
568 ptr[slen] = '\0';
569
570 dptr = ct_decode_string(ptr, &el->el_scratch);
571 if (!dptr)
572 continue;
573 /* loop until first non-space char or EOL */
574 while (*dptr != '\0' && iswspace(*dptr))
575 dptr++;
576 if (*dptr == '#')
577 continue; /* ignore, this is a comment line */
578 if ((error = parse_line(el, dptr)) == -1)
579 break;
580 }
581 free(ptr);
582
583 el_free(path);
584 (void) fclose(fp);
585 return error;
586 }
587
588
589 /* el_resize():
590 * Called from program when terminal is resized
591 */
592 void
593 el_resize(EditLine *el)
594 {
595 int lins, cols;
596 sigset_t oset, nset;
597
598 (void) sigemptyset(&nset);
599 (void) sigaddset(&nset, SIGWINCH);
600 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
601
602 /* get the correct window size */
603 if (terminal_get_size(el, &lins, &cols))
604 terminal_change_size(el, lins, cols);
605
606 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
607 }
608
609
610 /* el_beep():
611 * Called from the program to beep
612 */
613 void
614 el_beep(EditLine *el)
615 {
616
617 terminal_beep(el);
618 }
619
620
621 /* el_editmode()
622 * Set the state of EDIT_DISABLED from the `edit' command.
623 */
624 libedit_private int
625 /*ARGSUSED*/
626 el_editmode(EditLine *el, int argc, const wchar_t **argv)
627 {
628 const wchar_t *how;
629
630 if (argv == NULL || argc != 2 || argv[1] == NULL)
631 return -1;
632
633 how = argv[1];
634 if (wcscmp(how, L"on") == 0) {
635 el->el_flags &= ~EDIT_DISABLED;
636 tty_rawmode(el);
637 } else if (wcscmp(how, L"off") == 0) {
638 tty_cookedmode(el);
639 el->el_flags |= EDIT_DISABLED;
640 }
641 else {
642 (void) fprintf(el->el_errfile, "edit: Bad value `%ls'.\n",
643 how);
644 return -1;
645 }
646 return 0;
647 }
648