]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libedit/el.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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.44 2006/12/15 22:13:33 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_infile = fin;
70         el->el_outfile = fout;
71         el->el_errfile = ferr;
72
73         el->el_infd = fileno(fin);
74
75         if ((el->el_prog = el_strdup(prog)) == NULL) {
76                 el_free(el);
77                 return NULL;
78         }
79
80         /*
81          * Initialize all the modules. Order is important!!!
82          */
83         el->el_flags = 0;
84
85         if (term_init(el) == -1) {
86                 el_free(el->el_prog);
87                 el_free(el);
88                 return NULL;
89         }
90         (void) key_init(el);
91         (void) map_init(el);
92         if (tty_init(el) == -1)
93                 el->el_flags |= NO_TTY;
94         (void) ch_init(el);
95         (void) search_init(el);
96         (void) hist_init(el);
97         (void) prompt_init(el);
98         (void) sig_init(el);
99         (void) read_init(el);
100
101         return (el);
102 }
103
104
105 /* el_end():
106  *      Clean up.
107  */
108 public void
109 el_end(EditLine *el)
110 {
111
112         if (el == NULL)
113                 return;
114
115         el_reset(el);
116
117         term_end(el);
118         key_end(el);
119         map_end(el);
120         tty_end(el);
121         ch_end(el);
122         search_end(el);
123         hist_end(el);
124         prompt_end(el);
125         sig_end(el);
126
127         el_free((ptr_t) el->el_prog);
128         el_free((ptr_t) el);
129 }
130
131
132 /* el_reset():
133  *      Reset the tty and the parser
134  */
135 public void
136 el_reset(EditLine *el)
137 {
138
139         tty_cookedmode(el);
140         ch_reset(el, 0);                /* XXX: Do we want that? */
141 }
142
143
144 /* el_set():
145  *      set the editline parameters
146  */
147 public int
148 el_set(EditLine *el, int op, ...)
149 {
150         va_list ap;
151         int rv = 0;
152
153         if (el == NULL)
154                 return (-1);
155         va_start(ap, op);
156
157         switch (op) {
158         case EL_PROMPT:
159         case EL_RPROMPT:
160                 rv = prompt_set(el, va_arg(ap, el_pfunc_t), op);
161                 break;
162
163         case EL_TERMINAL:
164                 rv = term_set(el, va_arg(ap, char *));
165                 break;
166
167         case EL_EDITOR:
168                 rv = map_set_editor(el, va_arg(ap, char *));
169                 break;
170
171         case EL_SIGNAL:
172                 if (va_arg(ap, int))
173                         el->el_flags |= HANDLE_SIGNALS;
174                 else
175                         el->el_flags &= ~HANDLE_SIGNALS;
176                 break;
177
178         case EL_BIND:
179         case EL_TELLTC:
180         case EL_SETTC:
181         case EL_GETTC:
182         case EL_ECHOTC:
183         case EL_SETTY:
184         {
185                 const char *argv[20];
186                 int i;
187
188                 for (i = 1; i < 20; i++)
189                         if ((argv[i] = va_arg(ap, char *)) == NULL)
190                                 break;
191
192                 switch (op) {
193                 case EL_BIND:
194                         argv[0] = "bind";
195                         rv = map_bind(el, i, argv);
196                         break;
197
198                 case EL_TELLTC:
199                         argv[0] = "telltc";
200                         rv = term_telltc(el, i, argv);
201                         break;
202
203                 case EL_SETTC:
204                         argv[0] = "settc";
205                         rv = term_settc(el, i, argv);
206                         break;
207
208                 case EL_ECHOTC:
209                         argv[0] = "echotc";
210                         rv = term_echotc(el, i, argv);
211                         break;
212
213                 case EL_SETTY:
214                         argv[0] = "setty";
215                         rv = tty_stty(el, i, argv);
216                         break;
217
218                 default:
219                         rv = -1;
220                         EL_ABORT((el->el_errfile, "Bad op %d\n", op));
221                         break;
222                 }
223                 break;
224         }
225
226         case EL_ADDFN:
227         {
228                 char *name = va_arg(ap, char *);
229                 char *help = va_arg(ap, char *);
230                 el_func_t func = va_arg(ap, el_func_t);
231
232                 rv = map_addfunc(el, name, help, func);
233                 break;
234         }
235
236         case EL_HIST:
237         {
238                 hist_fun_t func = va_arg(ap, hist_fun_t);
239                 ptr_t ptr = va_arg(ap, char *);
240
241                 rv = hist_set(el, func, ptr);
242                 break;
243         }
244
245         case EL_EDITMODE:
246                 if (va_arg(ap, int))
247                         el->el_flags &= ~EDIT_DISABLED;
248                 else
249                         el->el_flags |= EDIT_DISABLED;
250                 rv = 0;
251                 break;
252
253         case EL_GETCFN:
254         {
255                 el_rfunc_t rc = va_arg(ap, el_rfunc_t);
256                 rv = el_read_setfn(el, rc);
257                 break;
258         }
259
260         case EL_CLIENTDATA:
261                 el->el_data = va_arg(ap, void *);
262                 break;
263
264         case EL_UNBUFFERED:
265                 rv = va_arg(ap, int);
266                 if (rv && !(el->el_flags & UNBUFFERED)) {
267                         el->el_flags |= UNBUFFERED;
268                         read_prepare(el);
269                 } else if (!rv && (el->el_flags & UNBUFFERED)) {
270                         el->el_flags &= ~UNBUFFERED;
271                         read_finish(el);
272                 }
273                 rv = 0;
274                 break;
275
276         case EL_PREP_TERM:
277                 rv = va_arg(ap, int);
278                 if (rv)
279                         (void) tty_rawmode(el);
280                 else
281                         (void) tty_cookedmode(el);
282                 rv = 0;
283                 break;
284
285         case EL_SETFP:
286         {
287                 FILE *fp;
288                 int what;
289
290                 what = va_arg(ap, int);
291                 fp = va_arg(ap, FILE *);
292
293                 rv = 0;
294                 switch (what) {
295                 case 0:
296                         el->el_infile = fp;
297                         el->el_infd = fileno(fp);
298                         break;
299                 case 1:
300                         el->el_outfile = fp;
301                         break;
302                 case 2:
303                         el->el_errfile = fp;
304                         break;
305                 default:
306                         rv = -1;
307                         break;
308                 }
309                 break;
310         }
311
312         default:
313                 rv = -1;
314                 break;
315         }
316
317         va_end(ap);
318         return (rv);
319 }
320
321
322 /* el_get():
323  *      retrieve the editline parameters
324  */
325 public int
326 el_get(EditLine *el, int op, ...)
327 {
328         va_list ap;
329         int rv;
330
331         if (el == NULL)
332                 return -1;
333
334         va_start(ap, op);
335
336         switch (op) {
337         case EL_PROMPT:
338         case EL_RPROMPT:
339                 rv = prompt_get(el, va_arg(ap, el_pfunc_t *), op);
340                 break;
341
342         case EL_EDITOR:
343                 rv = map_get_editor(el, va_arg(ap, const char **));
344                 break;
345
346         case EL_SIGNAL:
347                 *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
348                 rv = 0;
349                 break;
350
351         case EL_EDITMODE:
352                 *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
353                 rv = 0;
354                 break;
355
356         case EL_TERMINAL:
357                 term_get(el, va_arg(ap, const char **));
358                 rv = 0;
359                 break;
360
361         case EL_GETTC:
362         {
363                 static char name[] = "gettc";
364                 char *argv[20];
365                 int i;
366
367                 for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++)
368                         if ((argv[i] = va_arg(ap, char *)) == NULL)
369                                 break;
370
371                 switch (op) {
372                 case EL_GETTC:
373                         argv[0] = name;
374                         rv = term_gettc(el, i, argv);
375                         break;
376
377                 default:
378                         rv = -1;
379                         EL_ABORT((el->el_errfile, "Bad op %d\n", op));
380                         break;
381                 }
382                 break;
383         }
384
385 #if 0 /* XXX */
386         case EL_ADDFN:
387         {
388                 char *name = va_arg(ap, char *);
389                 char *help = va_arg(ap, char *);
390                 el_func_t func = va_arg(ap, el_func_t);
391
392                 rv = map_addfunc(el, name, help, func);
393                 break;
394         }
395
396         case EL_HIST:
397                 {
398                         hist_fun_t func = va_arg(ap, hist_fun_t);
399                         ptr_t ptr = va_arg(ap, char *);
400                         rv = hist_set(el, func, ptr);
401                 }
402                 break;
403 #endif /* XXX */
404
405         case EL_GETCFN:
406                 *va_arg(ap, el_rfunc_t *) = el_read_getfn(el);
407                 rv = 0;
408                 break;
409
410         case EL_CLIENTDATA:
411                 *va_arg(ap, void **) = el->el_data;
412                 rv = 0;
413                 break;
414
415         case EL_UNBUFFERED:
416                 *va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED));
417                 rv = 0;
418                 break;
419
420         case EL_GETFP:
421         {
422                 int what;
423                 FILE **fpp;
424
425                 what = va_arg(ap, int);
426                 fpp = va_arg(ap, FILE **);
427                 rv = 0;
428                 switch (what) {
429                 case 0:
430                         *fpp = el->el_infile;
431                         break;
432                 case 1:
433                         *fpp = el->el_outfile;
434                         break;
435                 case 2:
436                         *fpp = el->el_errfile;
437                         break;
438                 default:
439                         rv = -1;
440                         break;
441                 }
442                 break;
443         }
444         default:
445                 rv = -1;
446                 break;
447         }
448         va_end(ap);
449
450         return (rv);
451 }
452
453 /* el_data_get():
454  *      Set user private data.
455  */
456 public void
457 el_data_set (el, data)
458     EditLine *el;
459     void *data;
460 {
461     el->el_data = data;
462
463     return;
464 }
465
466 /* el_data_get():
467  *      Return user private data.
468  */
469 public void *
470 el_data_get (el)
471     EditLine *el;
472 {
473     if (el->el_data)
474         return (el->el_data);
475     return (NULL);
476 }
477
478 /* el_line():
479  *      Return editing info
480  */
481 public const LineInfo *
482 el_line(EditLine *el)
483 {
484
485         return (const LineInfo *) (void *) &el->el_line;
486 }
487
488
489 /* el_source():
490  *      Source a file
491  */
492 public int
493 el_source(EditLine *el, const char *fname)
494 {
495         FILE *fp;
496         size_t len;
497         char *ptr;
498
499         fp = NULL;
500         if (fname == NULL) {
501 #ifdef HAVE_ISSETUGID
502                 static const char elpath[] = "/.editrc";
503                 char path[MAXPATHLEN];
504
505                 if (issetugid())
506                         return (-1);
507                 if ((ptr = getenv("HOME")) == NULL)
508                         return (-1);
509                 if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
510                         return (-1);
511                 if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
512                         return (-1);
513                 fname = path;
514 #else
515                 /*
516                  * If issetugid() is missing, always return an error, in order
517                  * to keep from inadvertently opening up the user to a security
518                  * hole.
519                  */
520                 return (-1);
521 #endif
522         }
523         if (fp == NULL)
524                 fp = fopen(fname, "r");
525         if (fp == NULL)
526                 return (-1);
527
528         while ((ptr = fgetln(fp, &len)) != NULL) {
529                 if (len > 0 && ptr[len - 1] == '\n')
530                         --len;
531                 ptr[len] = '\0';
532                 if (parse_line(el, ptr) == -1) {
533                         (void) fclose(fp);
534                         return (-1);
535                 }
536         }
537
538         (void) fclose(fp);
539         return (0);
540 }
541
542
543 /* el_resize():
544  *      Called from program when terminal is resized
545  */
546 public void
547 el_resize(EditLine *el)
548 {
549         int lins, cols;
550         sigset_t oset, nset;
551
552         (void) sigemptyset(&nset);
553         (void) sigaddset(&nset, SIGWINCH);
554         (void) sigprocmask(SIG_BLOCK, &nset, &oset);
555
556         /* get the correct window size */
557         if (term_get_size(el, &lins, &cols))
558                 term_change_size(el, lins, cols);
559
560         (void) sigprocmask(SIG_SETMASK, &oset, NULL);
561 }
562
563
564 /* el_beep():
565  *      Called from the program to beep
566  */
567 public void
568 el_beep(EditLine *el)
569 {
570
571         term_beep(el);
572 }
573
574
575 /* el_editmode()
576  *      Set the state of EDIT_DISABLED from the `edit' command.
577  */
578 protected int
579 /*ARGSUSED*/
580 el_editmode(EditLine *el, int argc, const char **argv)
581 {
582         const char *how;
583
584         if (argv == NULL || argc != 2 || argv[1] == NULL)
585                 return (-1);
586
587         how = argv[1];
588         if (strcmp(how, "on") == 0) {
589                 el->el_flags &= ~EDIT_DISABLED;
590                 tty_rawmode(el);
591         } else if (strcmp(how, "off") == 0) {
592                 tty_cookedmode(el);
593                 el->el_flags |= EDIT_DISABLED;
594         }
595         else {
596                 (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how);
597                 return (-1);
598         }
599         return (0);
600 }