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