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