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