1 /* $NetBSD: el.c,v 1.68 2011/07/29 15:16:33 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 #endif
41 #endif /* not lint && not SCCSID */
42
43 /*
44 * el.c: EditLine interface functions
45 */
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <stdarg.h>
51 #include <ctype.h>
52 #include <locale.h>
53 #include <langinfo.h>
54 #include "el.h"
55
56 /* el_init():
57 * Initialize editline and set default parameters.
58 */
59 public EditLine *
el_init(const char * prog,FILE * fin,FILE * fout,FILE * ferr)60 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
61 {
62 EditLine *el = el_malloc(sizeof(*el));
63
64 if (el == NULL)
65 return NULL;
66
67 memset(el, 0, sizeof(EditLine));
68
69 el->el_infile = fin;
70 el->el_outfile = fout;
71 el->el_errfile = ferr;
72
73 el->el_infd = fileno(fin);
74 el->el_outfd = fileno(fout);
75 el->el_errfd = fileno(ferr);
76
77 el->el_prog = Strdup(ct_decode_string(prog, &el->el_scratch));
78 if (el->el_prog == NULL) {
79 el_free(el);
80 return NULL;
81 }
82
83 /*
84 * Initialize all the modules. Order is important!!!
85 */
86 el->el_flags = 0;
87 #ifdef WIDECHAR
88 setlocale(LC_CTYPE, NULL);
89 if (MB_CUR_MAX > 1)
90 el->el_flags |= CHARSET_IS_MULTIBYTE;
91 #endif
92
93 if (terminal_init(el) == -1) {
94 el_free(el->el_prog);
95 el_free(el);
96 return NULL;
97 }
98 (void) keymacro_init(el);
99 (void) map_init(el);
100 if (tty_init(el) == -1)
101 el->el_flags |= NO_TTY;
102 (void) ch_init(el);
103 (void) search_init(el);
104 (void) hist_init(el);
105 (void) prompt_init(el);
106 (void) sig_init(el);
107 (void) read_init(el);
108
109 return el;
110 }
111
112
113 /* el_end():
114 * Clean up.
115 */
116 public void
el_end(EditLine * el)117 el_end(EditLine *el)
118 {
119
120 if (el == NULL)
121 return;
122
123 el_reset(el);
124
125 terminal_end(el);
126 keymacro_end(el);
127 map_end(el);
128 tty_end(el);
129 ch_end(el);
130 search_end(el);
131 hist_end(el);
132 prompt_end(el);
133 sig_end(el);
134
135 el_free(el->el_prog);
136 #ifdef WIDECHAR
137 el_free(el->el_scratch.cbuff);
138 el_free(el->el_scratch.wbuff);
139 el_free(el->el_lgcyconv.cbuff);
140 el_free(el->el_lgcyconv.wbuff);
141 #endif
142 el_free(el);
143 }
144
145
146 /* el_reset():
147 * Reset the tty and the parser
148 */
149 public void
el_reset(EditLine * el)150 el_reset(EditLine *el)
151 {
152
153 tty_cookedmode(el);
154 ch_reset(el, 0); /* XXX: Do we want that? */
155 }
156
157
158 /* el_set():
159 * set the editline parameters
160 */
161 public int
FUN(el,set)162 FUN(el,set)(EditLine *el, int op, ...)
163 {
164 va_list ap;
165 int rv = 0;
166
167 if (el == NULL)
168 return -1;
169 va_start(ap, op);
170
171 switch (op) {
172 case EL_PROMPT:
173 case EL_RPROMPT: {
174 el_pfunc_t p = va_arg(ap, el_pfunc_t);
175
176 rv = prompt_set(el, p, 0, op, 1);
177 break;
178 }
179
180 case EL_RESIZE: {
181 el_zfunc_t p = va_arg(ap, el_zfunc_t);
182 void *arg = va_arg(ap, void *);
183 rv = ch_resizefun(el, p, arg);
184 break;
185 }
186
187 case EL_PROMPT_ESC:
188 case EL_RPROMPT_ESC: {
189 el_pfunc_t p = va_arg(ap, el_pfunc_t);
190 int c = va_arg(ap, int);
191
192 rv = prompt_set(el, p, c, op, 1);
193 break;
194 }
195
196 case EL_TERMINAL:
197 rv = terminal_set(el, va_arg(ap, char *));
198 break;
199
200 case EL_EDITOR:
201 rv = map_set_editor(el, va_arg(ap, Char *));
202 break;
203
204 case EL_SIGNAL:
205 if (va_arg(ap, int))
206 el->el_flags |= HANDLE_SIGNALS;
207 else
208 el->el_flags &= ~HANDLE_SIGNALS;
209 break;
210
211 case EL_BIND:
212 case EL_TELLTC:
213 case EL_SETTC:
214 case EL_ECHOTC:
215 case EL_SETTY:
216 {
217 const Char *argv[20];
218 int i;
219
220 for (i = 1; i < 20; i++)
221 if ((argv[i] = va_arg(ap, Char *)) == NULL)
222 break;
223
224 switch (op) {
225 case EL_BIND:
226 argv[0] = STR("bind");
227 rv = map_bind(el, i, argv);
228 break;
229
230 case EL_TELLTC:
231 argv[0] = STR("telltc");
232 rv = terminal_telltc(el, i, argv);
233 break;
234
235 case EL_SETTC:
236 argv[0] = STR("settc");
237 rv = terminal_settc(el, i, argv);
238 break;
239
240 case EL_ECHOTC:
241 argv[0] = STR("echotc");
242 rv = terminal_echotc(el, i, argv);
243 break;
244
245 case EL_SETTY:
246 argv[0] = STR("setty");
247 rv = tty_stty(el, i, argv);
248 break;
249
250 default:
251 rv = -1;
252 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
253 break;
254 }
255 break;
256 }
257
258 case EL_ADDFN:
259 {
260 Char *name = va_arg(ap, Char *);
261 Char *help = va_arg(ap, Char *);
262 el_func_t func = va_arg(ap, el_func_t);
263
264 rv = map_addfunc(el, name, help, func);
265 break;
266 }
267
268 case EL_HIST:
269 {
270 hist_fun_t func = va_arg(ap, hist_fun_t);
271 void *ptr = va_arg(ap, void *);
272
273 rv = hist_set(el, func, ptr);
274 if (!(el->el_flags & CHARSET_IS_MULTIBYTE))
275 el->el_flags &= ~NARROW_HISTORY;
276 break;
277 }
278
279 case EL_EDITMODE:
280 if (va_arg(ap, int))
281 el->el_flags &= ~EDIT_DISABLED;
282 else
283 el->el_flags |= EDIT_DISABLED;
284 rv = 0;
285 break;
286
287 case EL_GETCFN:
288 {
289 el_rfunc_t rc = va_arg(ap, el_rfunc_t);
290 rv = el_read_setfn(el, rc);
291 el->el_flags &= ~NARROW_READ;
292 break;
293 }
294
295 case EL_CLIENTDATA:
296 el->el_data = va_arg(ap, void *);
297 break;
298
299 case EL_UNBUFFERED:
300 rv = va_arg(ap, int);
301 if (rv && !(el->el_flags & UNBUFFERED)) {
302 el->el_flags |= UNBUFFERED;
303 read_prepare(el);
304 } else if (!rv && (el->el_flags & UNBUFFERED)) {
305 el->el_flags &= ~UNBUFFERED;
306 read_finish(el);
307 }
308 rv = 0;
309 break;
310
311 case EL_PREP_TERM:
312 rv = va_arg(ap, int);
313 if (rv)
314 (void) tty_rawmode(el);
315 else
316 (void) tty_cookedmode(el);
317 rv = 0;
318 break;
319
320 case EL_SETFP:
321 {
322 FILE *fp;
323 int what;
324
325 what = va_arg(ap, int);
326 fp = va_arg(ap, FILE *);
327
328 rv = 0;
329 switch (what) {
330 case 0:
331 el->el_infile = fp;
332 el->el_infd = fileno(fp);
333 break;
334 case 1:
335 el->el_outfile = fp;
336 el->el_outfd = fileno(fp);
337 break;
338 case 2:
339 el->el_errfile = fp;
340 el->el_errfd = fileno(fp);
341 break;
342 default:
343 rv = -1;
344 break;
345 }
346 break;
347 }
348
349 case EL_REFRESH:
350 re_clear_display(el);
351 re_refresh(el);
352 terminal__flush(el);
353 break;
354
355 default:
356 rv = -1;
357 break;
358 }
359
360 va_end(ap);
361 return rv;
362 }
363
364
365 /* el_get():
366 * retrieve the editline parameters
367 */
368 public int
FUN(el,get)369 FUN(el,get)(EditLine *el, int op, ...)
370 {
371 va_list ap;
372 int rv;
373
374 if (el == NULL)
375 return -1;
376
377 va_start(ap, op);
378
379 switch (op) {
380 case EL_PROMPT:
381 case EL_RPROMPT: {
382 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
383 rv = prompt_get(el, p, 0, op);
384 break;
385 }
386 case EL_PROMPT_ESC:
387 case EL_RPROMPT_ESC: {
388 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
389 Char *c = va_arg(ap, Char *);
390
391 rv = prompt_get(el, p, c, op);
392 break;
393 }
394
395 case EL_EDITOR:
396 rv = map_get_editor(el, va_arg(ap, const Char **));
397 break;
398
399 case EL_SIGNAL:
400 *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
401 rv = 0;
402 break;
403
404 case EL_EDITMODE:
405 *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
406 rv = 0;
407 break;
408
409 case EL_TERMINAL:
410 terminal_get(el, va_arg(ap, const char **));
411 rv = 0;
412 break;
413
414 case EL_GETTC:
415 {
416 static char name[] = "gettc";
417 char *argv[20];
418 int i;
419
420 for (i = 1; i < (int)(sizeof(argv) / sizeof(argv[0])); i++)
421 if ((argv[i] = va_arg(ap, char *)) == NULL)
422 break;
423
424 switch (op) {
425 case EL_GETTC:
426 argv[0] = name;
427 rv = terminal_gettc(el, i, argv);
428 break;
429
430 default:
431 rv = -1;
432 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
433 break;
434 }
435 break;
436 }
437
438 case EL_GETCFN:
439 *va_arg(ap, el_rfunc_t *) = el_read_getfn(el);
440 rv = 0;
441 break;
442
443 case EL_CLIENTDATA:
444 *va_arg(ap, void **) = el->el_data;
445 rv = 0;
446 break;
447
448 case EL_UNBUFFERED:
449 *va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED));
450 rv = 0;
451 break;
452
453 case EL_GETFP:
454 {
455 int what;
456 FILE **fpp;
457
458 what = va_arg(ap, int);
459 fpp = va_arg(ap, FILE **);
460 rv = 0;
461 switch (what) {
462 case 0:
463 *fpp = el->el_infile;
464 break;
465 case 1:
466 *fpp = el->el_outfile;
467 break;
468 case 2:
469 *fpp = el->el_errfile;
470 break;
471 default:
472 rv = -1;
473 break;
474 }
475 break;
476 }
477 default:
478 rv = -1;
479 break;
480 }
481 va_end(ap);
482
483 return rv;
484 }
485
486
487 /* el_line():
488 * Return editing info
489 */
TYPE(LineInfo)490 public const TYPE(LineInfo) *
491 FUN(el,line)(EditLine *el)
492 {
493
494 return (const TYPE(LineInfo) *)(void *)&el->el_line;
495 }
496
497
498 /* el_source():
499 * Source a file
500 */
501 public int
el_source(EditLine * el,const char * fname)502 el_source(EditLine *el, const char *fname)
503 {
504 FILE *fp;
505 size_t len;
506 char *ptr;
507 char *path = NULL;
508 const Char *dptr;
509 int error = 0;
510
511 fp = NULL;
512 if (fname == NULL) {
513 /* XXXMYSQL: Bug#49967 */
514 #if defined(HAVE_GETUID) && defined(HAVE_GETEUID) && \
515 defined(HAVE_GETGID) && defined(HAVE_GETEGID)
516 #define HAVE_IDENTITY_FUNCS 1
517 #endif
518
519 #if (defined(HAVE_ISSETUGID) || defined(HAVE_IDENTITY_FUNCS))
520 static const char elpath[] = "/.editrc";
521 size_t plen = sizeof(elpath);
522 /* XXXMYSQL: Portability fix (for which platforms?) */
523 #ifdef HAVE_ISSETUGID
524 if (issetugid())
525 return -1;
526 #elif defined(HAVE_IDENTITY_FUNCS)
527 if (getuid() != geteuid() || getgid() != getegid())
528 return (-1);
529 #endif
530 if ((ptr = getenv("HOME")) == NULL)
531 return -1;
532 plen += strlen(ptr);
533 if ((path = el_malloc(plen * sizeof(*path))) == NULL)
534 return -1;
535 (void)snprintf(path, plen, "%s%s", ptr, elpath);
536 fname = path;
537 #else
538 /*
539 * If issetugid() or the above mentioned get[e][u|g]id()
540 * functions are missing, always return an error, in order
541 * to keep from inadvertently opening up the user to a
542 * security hole.
543 */
544 return -1;
545 #endif
546 }
547 if (fp == NULL)
548 fp = fopen(fname, "r");
549 if (fp == NULL) {
550 el_free(path);
551 return -1;
552 }
553
554 while ((ptr = fgetln(fp, &len)) != NULL) {
555 if (*ptr == '\n')
556 continue; /* Empty line. */
557 dptr = ct_decode_string(ptr, &el->el_scratch);
558 if (!dptr)
559 continue;
560 if (len > 0 && dptr[len - 1] == '\n')
561 --len;
562
563 /* loop until first non-space char or EOL */
564 while (*dptr != '\0' && Isspace(*dptr))
565 dptr++;
566 if (*dptr == '#')
567 continue; /* ignore, this is a comment line */
568 if ((error = parse_line(el, dptr)) == -1)
569 break;
570 }
571
572 el_free(path);
573 (void) fclose(fp);
574 return error;
575 }
576
577
578 /* el_resize():
579 * Called from program when terminal is resized
580 */
581 public void
el_resize(EditLine * el)582 el_resize(EditLine *el)
583 {
584 int lins, cols;
585 sigset_t oset, nset;
586
587 (void) sigemptyset(&nset);
588 (void) sigaddset(&nset, SIGWINCH);
589 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
590
591 /* get the correct window size */
592 if (terminal_get_size(el, &lins, &cols))
593 terminal_change_size(el, lins, cols);
594
595 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
596 }
597
598
599 /* el_beep():
600 * Called from the program to beep
601 */
602 public void
el_beep(EditLine * el)603 el_beep(EditLine *el)
604 {
605
606 terminal_beep(el);
607 }
608
609
610 /* el_editmode()
611 * Set the state of EDIT_DISABLED from the `edit' command.
612 */
613 protected int
614 /*ARGSUSED*/
el_editmode(EditLine * el,int argc,const Char ** argv)615 el_editmode(EditLine *el, int argc, const Char **argv)
616 {
617 const Char *how;
618
619 if (argv == NULL || argc != 2 || argv[1] == NULL)
620 return -1;
621
622 how = argv[1];
623 if (Strcmp(how, STR("on")) == 0) {
624 el->el_flags &= ~EDIT_DISABLED;
625 tty_rawmode(el);
626 } else if (Strcmp(how, STR("off")) == 0) {
627 tty_cookedmode(el);
628 el->el_flags |= EDIT_DISABLED;
629 }
630 else {
631 (void) fprintf(el->el_errfile, "edit: Bad value `" FSTR "'.\n",
632 how);
633 return -1;
634 }
635 return 0;
636 }
637