]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libedit/el.c
This commit was generated by cvs2svn to compensate for changes in r169693,
[FreeBSD/FreeBSD.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  *      $NetBSD: el.c,v 1.41 2005/08/19 04:21:47 christos Exp $
33  */
34
35 #if !defined(lint) && !defined(SCCSID)
36 static char sccsid[] = "@(#)el.c        8.2 (Berkeley) 1/3/94";
37 #endif /* not lint && not SCCSID */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 /*
42  * el.c: EditLine interface functions
43  */
44 #include "sys.h"
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 "el.h"
52
53 #define HAVE_ISSETUGID
54
55 /* el_init():
56  *      Initialize editline and set default parameters.
57  */
58 public EditLine *
59 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
60 {
61
62         EditLine *el = (EditLine *) el_malloc(sizeof(EditLine));
63
64         if (el == NULL)
65                 return (NULL);
66
67         memset(el, 0, sizeof(EditLine));
68
69         el->el_infd = fileno(fin);
70         el->el_outfile = fout;
71         el->el_errfile = ferr;
72         if ((el->el_prog = el_strdup(prog)) == NULL) {
73                 el_free(el);
74                 return NULL;
75         }
76
77         /*
78          * Initialize all the modules. Order is important!!!
79          */
80         el->el_flags = 0;
81
82         if (term_init(el) == -1) {
83                 el_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         el_free((ptr_t) el->el_prog);
125         el_free((ptr_t) el);
126 }
127
128
129 /* el_reset():
130  *      Reset the tty and the parser
131  */
132 public void
133 el_reset(EditLine *el)
134 {
135
136         tty_cookedmode(el);
137         ch_reset(el, 0);                /* XXX: Do we want that? */
138 }
139
140
141 /* el_set():
142  *      set the editline parameters
143  */
144 public int
145 el_set(EditLine *el, int op, ...)
146 {
147         va_list va;
148         int rv = 0;
149
150         if (el == NULL)
151                 return (-1);
152         va_start(va, op);
153
154         switch (op) {
155         case EL_PROMPT:
156         case EL_RPROMPT:
157                 rv = prompt_set(el, va_arg(va, el_pfunc_t), op);
158                 break;
159
160         case EL_TERMINAL:
161                 rv = term_set(el, va_arg(va, char *));
162                 break;
163
164         case EL_EDITOR:
165                 rv = map_set_editor(el, va_arg(va, char *));
166                 break;
167
168         case EL_SIGNAL:
169                 if (va_arg(va, int))
170                         el->el_flags |= HANDLE_SIGNALS;
171                 else
172                         el->el_flags &= ~HANDLE_SIGNALS;
173                 break;
174
175         case EL_BIND:
176         case EL_TELLTC:
177         case EL_SETTC:
178         case EL_ECHOTC:
179         case EL_SETTY:
180         {
181                 const char *argv[20];
182                 int i;
183
184                 for (i = 1; i < 20; i++)
185                         if ((argv[i] = va_arg(va, char *)) == NULL)
186                                 break;
187
188                 switch (op) {
189                 case EL_BIND:
190                         argv[0] = "bind";
191                         rv = map_bind(el, i, argv);
192                         break;
193
194                 case EL_TELLTC:
195                         argv[0] = "telltc";
196                         rv = term_telltc(el, i, argv);
197                         break;
198
199                 case EL_SETTC:
200                         argv[0] = "settc";
201                         rv = term_settc(el, i, argv);
202                         break;
203
204                 case EL_ECHOTC:
205                         argv[0] = "echotc";
206                         rv = term_echotc(el, i, argv);
207                         break;
208
209                 case EL_SETTY:
210                         argv[0] = "setty";
211                         rv = tty_stty(el, i, argv);
212                         break;
213
214                 default:
215                         rv = -1;
216                         EL_ABORT((el->el_errfile, "Bad op %d\n", op));
217                         break;
218                 }
219                 break;
220         }
221
222         case EL_ADDFN:
223         {
224                 char *name = va_arg(va, char *);
225                 char *help = va_arg(va, char *);
226                 el_func_t func = va_arg(va, el_func_t);
227
228                 rv = map_addfunc(el, name, help, func);
229                 break;
230         }
231
232         case EL_HIST:
233         {
234                 hist_fun_t func = va_arg(va, hist_fun_t);
235                 ptr_t ptr = va_arg(va, char *);
236
237                 rv = hist_set(el, func, ptr);
238                 break;
239         }
240
241         case EL_EDITMODE:
242                 if (va_arg(va, int))
243                         el->el_flags &= ~EDIT_DISABLED;
244                 else
245                         el->el_flags |= EDIT_DISABLED;
246                 rv = 0;
247                 break;
248
249         case EL_GETCFN:
250         {
251                 el_rfunc_t rc = va_arg(va, el_rfunc_t);
252                 rv = el_read_setfn(el, rc);
253                 break;
254         }
255
256         case EL_CLIENTDATA:
257                 el->el_data = va_arg(va, void *);
258                 break;
259
260         case EL_UNBUFFERED:
261                 rv = va_arg(va, int);
262                 if (rv && !(el->el_flags & UNBUFFERED)) {
263                         el->el_flags |= UNBUFFERED;
264                         read_prepare(el);
265                 } else if (!rv && (el->el_flags & UNBUFFERED)) {
266                         el->el_flags &= ~UNBUFFERED;
267                         read_finish(el);
268                 }
269                 rv = 0;
270                 break;
271
272         case EL_PREP_TERM:
273                 rv = va_arg(va, int);
274                 if (rv)
275                         (void) tty_rawmode(el);
276                 else
277                         (void) tty_cookedmode(el);
278                 rv = 0;
279                 break;
280
281         default:
282                 rv = -1;
283                 break;
284         }
285
286         va_end(va);
287         return (rv);
288 }
289
290
291 /* el_get():
292  *      retrieve the editline parameters
293  */
294 public int
295 el_get(EditLine *el, int op, void *ret)
296 {
297         int rv;
298
299         if (el == NULL || ret == NULL)
300                 return (-1);
301         switch (op) {
302         case EL_PROMPT:
303         case EL_RPROMPT:
304                 rv = prompt_get(el, (el_pfunc_t *) ret, op);
305                 break;
306
307         case EL_EDITOR:
308                 rv = map_get_editor(el, (const char **)ret);
309                 break;
310
311         case EL_SIGNAL:
312                 *((int *) ret) = (el->el_flags & HANDLE_SIGNALS);
313                 rv = 0;
314                 break;
315
316         case EL_EDITMODE:
317                 *((int *) ret) = (!(el->el_flags & EDIT_DISABLED));
318                 rv = 0;
319                 break;
320
321         case EL_TERMINAL:
322                 term_get(el, (const char **)ret);
323                 rv = 0;
324                 break;
325
326 #if 0                           /* XXX */
327         case EL_BIND:
328         case EL_TELLTC:
329         case EL_SETTC:
330         case EL_ECHOTC:
331         case EL_SETTY:
332         {
333                 const char *argv[20];
334                 int i;
335
336                 for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++)
337                         if ((argv[i] = va_arg(va, char *)) == NULL)
338                                 break;
339
340                 switch (op) {
341                 case EL_BIND:
342                         argv[0] = "bind";
343                         rv = map_bind(el, i, argv);
344                         break;
345
346                 case EL_TELLTC:
347                         argv[0] = "telltc";
348                         rv = term_telltc(el, i, argv);
349                         break;
350
351                 case EL_SETTC:
352                         argv[0] = "settc";
353                         rv = term_settc(el, i, argv);
354                         break;
355
356                 case EL_ECHOTC:
357                         argv[0] = "echotc";
358                         rv = term_echotc(el, i, argv);
359                         break;
360
361                 case EL_SETTY:
362                         argv[0] = "setty";
363                         rv = tty_stty(el, i, argv);
364                         break;
365
366                 default:
367                         rv = -1;
368                         EL_ABORT((el->errfile, "Bad op %d\n", op));
369                         break;
370                 }
371                 break;
372         }
373
374         case EL_ADDFN:
375         {
376                 char *name = va_arg(va, char *);
377                 char *help = va_arg(va, char *);
378                 el_func_t func = va_arg(va, el_func_t);
379
380                 rv = map_addfunc(el, name, help, func);
381                 break;
382         }
383
384         case EL_HIST:
385                 {
386                         hist_fun_t func = va_arg(va, hist_fun_t);
387                         ptr_t ptr = va_arg(va, char *);
388                         rv = hist_set(el, func, ptr);
389                 }
390                 break;
391 #endif /* XXX */
392
393         case EL_GETCFN:
394                 *((el_rfunc_t *)ret) = el_read_getfn(el);
395                 rv = 0;
396                 break;
397
398         case EL_CLIENTDATA:
399                 *((void **)ret) = el->el_data;
400                 rv = 0;
401                 break;
402
403         case EL_UNBUFFERED:
404                 *((int *) ret) = (!(el->el_flags & UNBUFFERED));
405                 rv = 0;
406                 break;
407
408         default:
409                 rv = -1;
410         }
411
412         return (rv);
413 }
414
415 /* el_data_get():
416  *      Set user private data.
417  */
418 public void
419 el_data_set (el, data)
420     EditLine *el;
421     void *data;
422 {
423     el->el_data = data;
424
425     return;
426 }
427
428 /* el_data_get():
429  *      Return user private data.
430  */
431 public void *
432 el_data_get (el)
433     EditLine *el;
434 {
435     if (el->el_data)
436         return (el->el_data);
437     return (NULL);
438 }
439
440 /* el_line():
441  *      Return editing info
442  */
443 public const LineInfo *
444 el_line(EditLine *el)
445 {
446
447         return (const LineInfo *) (void *) &el->el_line;
448 }
449
450
451 /* el_source():
452  *      Source a file
453  */
454 public int
455 el_source(EditLine *el, const char *fname)
456 {
457         FILE *fp;
458         size_t len;
459         char *ptr;
460
461         fp = NULL;
462         if (fname == NULL) {
463 #ifdef HAVE_ISSETUGID
464                 static const char elpath[] = "/.editrc";
465                 char path[MAXPATHLEN];
466
467                 if (issetugid())
468                         return (-1);
469                 if ((ptr = getenv("HOME")) == NULL)
470                         return (-1);
471                 if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
472                         return (-1);
473                 if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
474                         return (-1);
475                 fname = path;
476 #else
477                 /*
478                  * If issetugid() is missing, always return an error, in order
479                  * to keep from inadvertently opening up the user to a security
480                  * hole.
481                  */
482                 return (-1);
483 #endif
484         }
485         if (fp == NULL)
486                 fp = fopen(fname, "r");
487         if (fp == NULL)
488                 return (-1);
489
490         while ((ptr = fgetln(fp, &len)) != NULL) {
491                 if (len > 0 && ptr[len - 1] == '\n')
492                         --len;
493                 ptr[len] = '\0';
494                 if (parse_line(el, ptr) == -1) {
495                         (void) fclose(fp);
496                         return (-1);
497                 }
498         }
499
500         (void) fclose(fp);
501         return (0);
502 }
503
504
505 /* el_resize():
506  *      Called from program when terminal is resized
507  */
508 public void
509 el_resize(EditLine *el)
510 {
511         int lins, cols;
512         sigset_t oset, nset;
513
514         (void) sigemptyset(&nset);
515         (void) sigaddset(&nset, SIGWINCH);
516         (void) sigprocmask(SIG_BLOCK, &nset, &oset);
517
518         /* get the correct window size */
519         if (term_get_size(el, &lins, &cols))
520                 term_change_size(el, lins, cols);
521
522         (void) sigprocmask(SIG_SETMASK, &oset, NULL);
523 }
524
525
526 /* el_beep():
527  *      Called from the program to beep
528  */
529 public void
530 el_beep(EditLine *el)
531 {
532
533         term_beep(el);
534 }
535
536
537 /* el_editmode()
538  *      Set the state of EDIT_DISABLED from the `edit' command.
539  */
540 protected int
541 /*ARGSUSED*/
542 el_editmode(EditLine *el, int argc, const char **argv)
543 {
544         const char *how;
545
546         if (argv == NULL || argc != 2 || argv[1] == NULL)
547                 return (-1);
548
549         how = argv[1];
550         if (strcmp(how, "on") == 0) {
551                 el->el_flags &= ~EDIT_DISABLED;
552                 tty_rawmode(el);
553         } else if (strcmp(how, "off") == 0) {
554                 tty_cookedmode(el);
555                 el->el_flags |= EDIT_DISABLED;
556         }
557         else {
558                 (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how);
559                 return (-1);
560         }
561         return (0);
562 }