el.c revision 1.60 1 /* $NetBSD: el.c,v 1.60 2010/08/28 15:44:59 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.60 2010/08/28 15:44:59 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 <string.h>
50 #include <stdlib.h>
51 #include <stdarg.h>
52 #include <ctype.h>
53 #include <locale.h>
54 #include <langinfo.h>
55 #include "el.h"
56
57 /* el_init():
58 * Initialize editline and set default parameters.
59 */
60 public EditLine *
61 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
62 {
63 EditLine *el = (EditLine *) el_malloc(sizeof(EditLine));
64
65 if (el == NULL)
66 return (NULL);
67
68 memset(el, 0, sizeof(EditLine));
69
70 el->el_infile = fin;
71 el->el_outfile = fout;
72 el->el_errfile = ferr;
73
74 el->el_infd = fileno(fin);
75
76 el->el_prog = Strdup(ct_decode_string(prog, &el->el_scratch));
77 if (el->el_prog == NULL) {
78 el_free(el);
79 return NULL;
80 }
81
82 /*
83 * Initialize all the modules. Order is important!!!
84 */
85 el->el_flags = 0;
86 #ifdef WIDECHAR
87 if (setlocale(LC_CTYPE, NULL) != NULL){
88 if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
89 el->el_flags |= CHARSET_IS_UTF8;
90 }
91 #endif
92
93 if (term_init(el) == -1) {
94 el_free(el->el_prog);
95 el_free(el);
96 return NULL;
97 }
98 (void) key_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
117 el_end(EditLine *el)
118 {
119
120 if (el == NULL)
121 return;
122
123 el_reset(el);
124
125 term_end(el);
126 key_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((ptr_t) el->el_prog);
136 el_free((ptr_t) el);
137 #ifdef WIDECHAR
138 el_free((ptr_t) el->el_scratch.cbuff);
139 el_free((ptr_t) el->el_scratch.wbuff);
140 el_free((ptr_t) el->el_lgcyconv.cbuff);
141 el_free((ptr_t) el->el_lgcyconv.wbuff);
142 #endif
143 }
144
145
146 /* el_reset():
147 * Reset the tty and the parser
148 */
149 public void
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
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 = term_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 = term_telltc(el, i, argv);
233 break;
234
235 case EL_SETTC:
236 argv[0] = STR("settc");
237 rv = term_settc(el, i, argv);
238 break;
239
240 case EL_ECHOTC:
241 argv[0] = STR("echotc");
242 rv = term_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 ptr_t ptr = va_arg(ap, ptr_t);
272
273 rv = hist_set(el, func, ptr);
274 if (!(el->el_flags & CHARSET_IS_UTF8))
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 break;
337 case 2:
338 el->el_errfile = fp;
339 break;
340 default:
341 rv = -1;
342 break;
343 }
344 break;
345 }
346
347 case EL_REFRESH:
348 re_clear_display(el);
349 re_refresh(el);
350 term__flush(el);
351 break;
352
353 default:
354 rv = -1;
355 break;
356 }
357
358 va_end(ap);
359 return (rv);
360 }
361
362
363 /* el_get():
364 * retrieve the editline parameters
365 */
366 public int
367 FUN(el,get)(EditLine *el, int op, ...)
368 {
369 va_list ap;
370 int rv;
371
372 if (el == NULL)
373 return -1;
374
375 va_start(ap, op);
376
377 switch (op) {
378 case EL_PROMPT:
379 case EL_RPROMPT: {
380 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
381 rv = prompt_get(el, p, 0, op);
382 break;
383 }
384 case EL_PROMPT_ESC:
385 case EL_RPROMPT_ESC: {
386 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
387 Char *c = va_arg(ap, Char *);
388
389 rv = prompt_get(el, p, c, op);
390 break;
391 }
392
393 case EL_EDITOR:
394 rv = map_get_editor(el, va_arg(ap, const Char **));
395 break;
396
397 case EL_SIGNAL:
398 *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
399 rv = 0;
400 break;
401
402 case EL_EDITMODE:
403 *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
404 rv = 0;
405 break;
406
407 case EL_TERMINAL:
408 term_get(el, va_arg(ap, const char **));
409 rv = 0;
410 break;
411
412 case EL_GETTC:
413 {
414 static char name[] = "gettc";
415 char *argv[20];
416 int i;
417
418 for (i = 1; i < (int)(sizeof(argv) / sizeof(argv[0])); i++)
419 if ((argv[i] = va_arg(ap, char *)) == NULL)
420 break;
421
422 switch (op) {
423 case EL_GETTC:
424 argv[0] = name;
425 rv = term_gettc(el, i, argv);
426 break;
427
428 default:
429 rv = -1;
430 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
431 break;
432 }
433 break;
434 }
435
436 case EL_GETCFN:
437 *va_arg(ap, el_rfunc_t *) = el_read_getfn(el);
438 rv = 0;
439 break;
440
441 case EL_CLIENTDATA:
442 *va_arg(ap, void **) = el->el_data;
443 rv = 0;
444 break;
445
446 case EL_UNBUFFERED:
447 *va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED));
448 rv = 0;
449 break;
450
451 case EL_GETFP:
452 {
453 int what;
454 FILE **fpp;
455
456 what = va_arg(ap, int);
457 fpp = va_arg(ap, FILE **);
458 rv = 0;
459 switch (what) {
460 case 0:
461 *fpp = el->el_infile;
462 break;
463 case 1:
464 *fpp = el->el_outfile;
465 break;
466 case 2:
467 *fpp = el->el_errfile;
468 break;
469 default:
470 rv = -1;
471 break;
472 }
473 break;
474 }
475 default:
476 rv = -1;
477 break;
478 }
479 va_end(ap);
480
481 return (rv);
482 }
483
484
485 /* el_line():
486 * Return editing info
487 */
488 public const TYPE(LineInfo) *
489 FUN(el,line)(EditLine *el)
490 {
491
492 return (const TYPE(LineInfo) *) (void *) &el->el_line;
493 }
494
495
496 /* el_source():
497 * Source a file
498 */
499 public int
500 el_source(EditLine *el, const char *fname)
501 {
502 FILE *fp;
503 size_t len;
504 char *ptr;
505 #ifdef HAVE_ISSETUGID
506 char path[MAXPATHLEN];
507 #endif
508 const Char *dptr;
509
510 fp = NULL;
511 if (fname == NULL) {
512 #ifdef HAVE_ISSETUGID
513 static const char elpath[] = "/.editrc";
514
515 if (issetugid())
516 return (-1);
517 if ((ptr = getenv("HOME")) == NULL)
518 return (-1);
519 if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
520 return (-1);
521 if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
522 return (-1);
523 fname = path;
524 #else
525 /*
526 * If issetugid() is missing, always return an error, in order
527 * to keep from inadvertently opening up the user to a security
528 * hole.
529 */
530 return (-1);
531 #endif
532 }
533 if (fp == NULL)
534 fp = fopen(fname, "r");
535 if (fp == NULL)
536 return (-1);
537
538 while ((ptr = fgetln(fp, &len)) != NULL) {
539 dptr = ct_decode_string(ptr, &el->el_scratch);
540 if (!dptr)
541 continue;
542 if (len > 0 && dptr[len - 1] == '\n')
543 --len;
544
545 /* loop until first non-space char or EOL */
546 while (*dptr != '\0' && Isspace(*dptr))
547 dptr++;
548 if (*dptr == '#')
549 continue; /* ignore, this is a comment line */
550 if (parse_line(el, dptr) == -1) {
551 (void) fclose(fp);
552 return (-1);
553 }
554 }
555
556 (void) fclose(fp);
557 return (0);
558 }
559
560
561 /* el_resize():
562 * Called from program when terminal is resized
563 */
564 public void
565 el_resize(EditLine *el)
566 {
567 int lins, cols;
568 sigset_t oset, nset;
569
570 (void) sigemptyset(&nset);
571 (void) sigaddset(&nset, SIGWINCH);
572 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
573
574 /* get the correct window size */
575 if (term_get_size(el, &lins, &cols))
576 term_change_size(el, lins, cols);
577
578 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
579 }
580
581
582 /* el_beep():
583 * Called from the program to beep
584 */
585 public void
586 el_beep(EditLine *el)
587 {
588
589 term_beep(el);
590 }
591
592
593 /* el_editmode()
594 * Set the state of EDIT_DISABLED from the `edit' command.
595 */
596 protected int
597 /*ARGSUSED*/
598 el_editmode(EditLine *el, int argc, const Char **argv)
599 {
600 const Char *how;
601
602 if (argv == NULL || argc != 2 || argv[1] == NULL)
603 return (-1);
604
605 how = argv[1];
606 if (Strcmp(how, STR("on")) == 0) {
607 el->el_flags &= ~EDIT_DISABLED;
608 tty_rawmode(el);
609 } else if (Strcmp(how, STR("off")) == 0) {
610 tty_cookedmode(el);
611 el->el_flags |= EDIT_DISABLED;
612 }
613 else {
614 (void) fprintf(el->el_errfile, "edit: Bad value `" FSTR "'.\n",
615 how);
616 return (-1);
617 }
618 return (0);
619 }
620