]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libedit/el.c
MFV r310622:
[FreeBSD/FreeBSD.git] / lib / libedit / el.c
1 /*      $NetBSD: el.c,v 1.74 2015/12/08 12:56:55 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. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)el.c        8.2 (Berkeley) 1/3/94";
39 #else
40 __RCSID("$NetBSD: el.c,v 1.74 2015/12/08 12:56:55 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 /*
47  * el.c: EditLine interface functions
48  */
49 #include <sys/types.h>
50 #include <sys/param.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <ctype.h>
55 #include <locale.h>
56 #include <langinfo.h>
57 #include "el.h"
58
59 /* el_init():
60  *      Initialize editline and set default parameters.
61  */
62 public EditLine *
63 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
64 {
65     return el_init_fd(prog, fin, fout, ferr, fileno(fin), fileno(fout),
66         fileno(ferr));
67 }
68
69 public EditLine *
70 el_init_fd(const char *prog, FILE *fin, FILE *fout, FILE *ferr,
71     int fdin, int fdout, int fderr)
72 {
73         EditLine *el = el_malloc(sizeof(*el));
74
75         if (el == NULL)
76                 return NULL;
77
78         memset(el, 0, sizeof(EditLine));
79
80         el->el_infile = fin;
81         el->el_outfile = fout;
82         el->el_errfile = ferr;
83
84         el->el_infd = fdin;
85         el->el_outfd = fdout;
86         el->el_errfd = fderr;
87
88         el->el_prog = Strdup(ct_decode_string(prog, &el->el_scratch));
89         if (el->el_prog == NULL) {
90                 el_free(el);
91                 return NULL;
92         }
93
94         /*
95          * Initialize all the modules. Order is important!!!
96          */
97         el->el_flags = 0;
98 #ifdef WIDECHAR
99         if (setlocale(LC_CTYPE, NULL) != NULL){
100                 if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
101                         el->el_flags |= CHARSET_IS_UTF8;
102         }
103 #endif
104
105         if (terminal_init(el) == -1) {
106                 el_free(el->el_prog);
107                 el_free(el);
108                 return NULL;
109         }
110         (void) keymacro_init(el);
111         (void) map_init(el);
112         if (tty_init(el) == -1)
113                 el->el_flags |= NO_TTY;
114         (void) ch_init(el);
115         (void) search_init(el);
116         (void) hist_init(el);
117         (void) prompt_init(el);
118         (void) sig_init(el);
119         (void) read_init(el);
120
121         return el;
122 }
123
124
125 /* el_end():
126  *      Clean up.
127  */
128 public void
129 el_end(EditLine *el)
130 {
131
132         if (el == NULL)
133                 return;
134
135         el_reset(el);
136
137         terminal_end(el);
138         keymacro_end(el);
139         map_end(el);
140         if (!(el->el_flags & NO_TTY))
141                 tty_end(el);
142         ch_end(el);
143         search_end(el);
144         hist_end(el);
145         prompt_end(el);
146         sig_end(el);
147
148         el_free(el->el_prog);
149 #ifdef WIDECHAR
150         el_free(el->el_scratch.cbuff);
151         el_free(el->el_scratch.wbuff);
152         el_free(el->el_lgcyconv.cbuff);
153         el_free(el->el_lgcyconv.wbuff);
154 #endif
155         el_free(el);
156 }
157
158
159 /* el_reset():
160  *      Reset the tty and the parser
161  */
162 public void
163 el_reset(EditLine *el)
164 {
165
166         tty_cookedmode(el);
167         ch_reset(el, 0);                /* XXX: Do we want that? */
168 }
169
170
171 /* el_set():
172  *      set the editline parameters
173  */
174 public int
175 FUN(el,set)(EditLine *el, int op, ...)
176 {
177         va_list ap;
178         int rv = 0;
179
180         if (el == NULL)
181                 return -1;
182         va_start(ap, op);
183
184         switch (op) {
185         case EL_PROMPT:
186         case EL_RPROMPT: {
187                 el_pfunc_t p = va_arg(ap, el_pfunc_t);
188
189                 rv = prompt_set(el, p, 0, op, 1);
190                 break;
191         }
192
193         case EL_RESIZE: {
194                 el_zfunc_t p = va_arg(ap, el_zfunc_t);
195                 void *arg = va_arg(ap, void *);
196                 rv = ch_resizefun(el, p, arg);
197                 break;
198         }
199
200         case EL_ALIAS_TEXT: {
201                 el_afunc_t p = va_arg(ap, el_afunc_t);
202                 void *arg = va_arg(ap, void *);
203                 rv = ch_aliasfun(el, p, arg);
204                 break;
205         }
206
207         case EL_PROMPT_ESC:
208         case EL_RPROMPT_ESC: {
209                 el_pfunc_t p = va_arg(ap, el_pfunc_t);
210                 int c = va_arg(ap, int);
211
212                 rv = prompt_set(el, p, c, op, 1);
213                 break;
214         }
215
216         case EL_TERMINAL:
217                 rv = terminal_set(el, va_arg(ap, char *));
218                 break;
219
220         case EL_EDITOR:
221                 rv = map_set_editor(el, va_arg(ap, Char *));
222                 break;
223
224         case EL_SIGNAL:
225                 if (va_arg(ap, int))
226                         el->el_flags |= HANDLE_SIGNALS;
227                 else
228                         el->el_flags &= ~HANDLE_SIGNALS;
229                 break;
230
231         case EL_BIND:
232         case EL_TELLTC:
233         case EL_SETTC:
234         case EL_ECHOTC:
235         case EL_SETTY:
236         {
237                 const Char *argv[20];
238                 int i;
239
240                 for (i = 1; i < (int)__arraycount(argv); i++)
241                         if ((argv[i] = va_arg(ap, Char *)) == NULL)
242                                 break;
243
244                 switch (op) {
245                 case EL_BIND:
246                         argv[0] = STR("bind");
247                         rv = map_bind(el, i, argv);
248                         break;
249
250                 case EL_TELLTC:
251                         argv[0] = STR("telltc");
252                         rv = terminal_telltc(el, i, argv);
253                         break;
254
255                 case EL_SETTC:
256                         argv[0] = STR("settc");
257                         rv = terminal_settc(el, i, argv);
258                         break;
259
260                 case EL_ECHOTC:
261                         argv[0] = STR("echotc");
262                         rv = terminal_echotc(el, i, argv);
263                         break;
264
265                 case EL_SETTY:
266                         argv[0] = STR("setty");
267                         rv = tty_stty(el, i, argv);
268                         break;
269
270                 default:
271                         rv = -1;
272                         EL_ABORT((el->el_errfile, "Bad op %d\n", op));
273                         break;
274                 }
275                 break;
276         }
277
278         case EL_ADDFN:
279         {
280                 Char *name = va_arg(ap, Char *);
281                 Char *help = va_arg(ap, Char *);
282                 el_func_t func = va_arg(ap, el_func_t);
283
284                 rv = map_addfunc(el, name, help, func);
285                 break;
286         }
287
288         case EL_HIST:
289         {
290                 hist_fun_t func = va_arg(ap, hist_fun_t);
291                 void *ptr = va_arg(ap, void *);
292
293                 rv = hist_set(el, func, ptr);
294                 if (!(el->el_flags & CHARSET_IS_UTF8))
295                         el->el_flags &= ~NARROW_HISTORY;
296                 break;
297         }
298
299         case EL_EDITMODE:
300                 if (va_arg(ap, int))
301                         el->el_flags &= ~EDIT_DISABLED;
302                 else
303                         el->el_flags |= EDIT_DISABLED;
304                 rv = 0;
305                 break;
306
307         case EL_GETCFN:
308         {
309                 el_rfunc_t rc = va_arg(ap, el_rfunc_t);
310                 rv = el_read_setfn(el, rc);
311                 el->el_flags &= ~NARROW_READ;
312                 break;
313         }
314
315         case EL_CLIENTDATA:
316                 el->el_data = va_arg(ap, void *);
317                 break;
318
319         case EL_UNBUFFERED:
320                 rv = va_arg(ap, int);
321                 if (rv && !(el->el_flags & UNBUFFERED)) {
322                         el->el_flags |= UNBUFFERED;
323                         read_prepare(el);
324                 } else if (!rv && (el->el_flags & UNBUFFERED)) {
325                         el->el_flags &= ~UNBUFFERED;
326                         read_finish(el);
327                 }
328                 rv = 0;
329                 break;
330
331         case EL_PREP_TERM:
332                 rv = va_arg(ap, int);
333                 if (rv)
334                         (void) tty_rawmode(el);
335                 else
336                         (void) tty_cookedmode(el);
337                 rv = 0;
338                 break;
339
340         case EL_SETFP:
341         {
342                 FILE *fp;
343                 int what;
344
345                 what = va_arg(ap, int);
346                 fp = va_arg(ap, FILE *);
347
348                 rv = 0;
349                 switch (what) {
350                 case 0:
351                         el->el_infile = fp;
352                         el->el_infd = fileno(fp);
353                         break;
354                 case 1:
355                         el->el_outfile = fp;
356                         el->el_outfd = fileno(fp);
357                         break;
358                 case 2:
359                         el->el_errfile = fp;
360                         el->el_errfd = fileno(fp);
361                         break;
362                 default:
363                         rv = -1;
364                         break;
365                 }
366                 break;
367         }
368
369         case EL_REFRESH:
370                 re_clear_display(el);
371                 re_refresh(el);
372                 terminal__flush(el);
373                 break;
374
375         default:
376                 rv = -1;
377                 break;
378         }
379
380         va_end(ap);
381         return rv;
382 }
383
384
385 /* el_get():
386  *      retrieve the editline parameters
387  */
388 public int
389 FUN(el,get)(EditLine *el, int op, ...)
390 {
391         va_list ap;
392         int rv;
393
394         if (el == NULL)
395                 return -1;
396
397         va_start(ap, op);
398
399         switch (op) {
400         case EL_PROMPT:
401         case EL_RPROMPT: {
402                 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
403                 rv = prompt_get(el, p, 0, op);
404                 break;
405         }
406         case EL_PROMPT_ESC:
407         case EL_RPROMPT_ESC: {
408                 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
409                 Char *c = va_arg(ap, Char *);
410
411                 rv = prompt_get(el, p, c, op);
412                 break;
413         }
414
415         case EL_EDITOR:
416                 rv = map_get_editor(el, va_arg(ap, const Char **));
417                 break;
418
419         case EL_SIGNAL:
420                 *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
421                 rv = 0;
422                 break;
423
424         case EL_EDITMODE:
425                 *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
426                 rv = 0;
427                 break;
428
429         case EL_TERMINAL:
430                 terminal_get(el, va_arg(ap, const char **));
431                 rv = 0;
432                 break;
433
434         case EL_GETTC:
435         {
436                 static char name[] = "gettc";
437                 char *argv[20];
438                 int i;
439
440                 for (i = 1; i < (int)__arraycount(argv); i++)
441                         if ((argv[i] = va_arg(ap, char *)) == NULL)
442                                 break;
443
444                 argv[0] = name;
445                 rv = terminal_gettc(el, i, argv);
446                 break;
447         }
448
449         case EL_GETCFN:
450                 *va_arg(ap, el_rfunc_t *) = el_read_getfn(el);
451                 rv = 0;
452                 break;
453
454         case EL_CLIENTDATA:
455                 *va_arg(ap, void **) = el->el_data;
456                 rv = 0;
457                 break;
458
459         case EL_UNBUFFERED:
460                 *va_arg(ap, int *) = (el->el_flags & UNBUFFERED) != 0;
461                 rv = 0;
462                 break;
463
464         case EL_GETFP:
465         {
466                 int what;
467                 FILE **fpp;
468
469                 what = va_arg(ap, int);
470                 fpp = va_arg(ap, FILE **);
471                 rv = 0;
472                 switch (what) {
473                 case 0:
474                         *fpp = el->el_infile;
475                         break;
476                 case 1:
477                         *fpp = el->el_outfile;
478                         break;
479                 case 2:
480                         *fpp = el->el_errfile;
481                         break;
482                 default:
483                         rv = -1;
484                         break;
485                 }
486                 break;
487         }
488         default:
489                 rv = -1;
490                 break;
491         }
492         va_end(ap);
493
494         return rv;
495 }
496
497
498 /* el_line():
499  *      Return editing info
500  */
501 public const TYPE(LineInfo) *
502 FUN(el,line)(EditLine *el)
503 {
504
505         return (const TYPE(LineInfo) *)(void *)&el->el_line;
506 }
507
508
509 /* el_source():
510  *      Source a file
511  */
512 public int
513 el_source(EditLine *el, const char *fname)
514 {
515         FILE *fp;
516         size_t len;
517         char *ptr;
518         char *path = NULL;
519         const Char *dptr;
520         int error = 0;
521
522         fp = NULL;
523         if (fname == NULL) {
524 #ifdef HAVE_ISSETUGID
525                 static const char elpath[] = "/.editrc";
526                 size_t plen = sizeof(elpath);
527
528                 if (issetugid())
529                         return -1;
530                 if ((ptr = getenv("HOME")) == NULL)
531                         return -1;
532                 plen += strlen(ptr);
533                 if ((path = el_malloc(plen * sizeof(*path))) == NULL)
534                         return -1;
535                 (void)snprintf(path, plen, "%s%s", ptr, elpath);
536                 fname = path;
537 #else
538                 /*
539                  * If issetugid() is missing, always return an error, in order
540                  * to keep from inadvertently opening up the user to a security
541                  * hole.
542                  */
543                 return -1;
544 #endif
545         }
546         if (fp == NULL)
547                 fp = fopen(fname, "r");
548         if (fp == NULL) {
549                 el_free(path);
550                 return -1;
551         }
552
553         while ((ptr = fgetln(fp, &len)) != NULL) {
554                 if (*ptr == '\n')
555                         continue;       /* Empty line. */
556                 dptr = ct_decode_string(ptr, &el->el_scratch);
557                 if (!dptr)
558                         continue;
559                 if (len > 0 && dptr[len - 1] == '\n')
560                         --len;
561
562                 /* loop until first non-space char or EOL */
563                 while (*dptr != '\0' && Isspace(*dptr))
564                         dptr++;
565                 if (*dptr == '#')
566                         continue;   /* ignore, this is a comment line */
567                 if ((error = parse_line(el, dptr)) == -1)
568                         break;
569         }
570
571         el_free(path);
572         (void) fclose(fp);
573         return error;
574 }
575
576
577 /* el_resize():
578  *      Called from program when terminal is resized
579  */
580 public void
581 el_resize(EditLine *el)
582 {
583         int lins, cols;
584         sigset_t oset, nset;
585
586         (void) sigemptyset(&nset);
587         (void) sigaddset(&nset, SIGWINCH);
588         (void) sigprocmask(SIG_BLOCK, &nset, &oset);
589
590         /* get the correct window size */
591         if (terminal_get_size(el, &lins, &cols))
592                 terminal_change_size(el, lins, cols);
593
594         (void) sigprocmask(SIG_SETMASK, &oset, NULL);
595 }
596
597
598 /* el_beep():
599  *      Called from the program to beep
600  */
601 public void
602 el_beep(EditLine *el)
603 {
604
605         terminal_beep(el);
606 }
607
608
609 /* el_editmode()
610  *      Set the state of EDIT_DISABLED from the `edit' command.
611  */
612 protected int
613 /*ARGSUSED*/
614 el_editmode(EditLine *el, int argc, const Char **argv)
615 {
616         const Char *how;
617
618         if (argv == NULL || argc != 2 || argv[1] == NULL)
619                 return -1;
620
621         how = argv[1];
622         if (Strcmp(how, STR("on")) == 0) {
623                 el->el_flags &= ~EDIT_DISABLED;
624                 tty_rawmode(el);
625         } else if (Strcmp(how, STR("off")) == 0) {
626                 tty_cookedmode(el);
627                 el->el_flags |= EDIT_DISABLED;
628         }
629         else {
630                 (void) fprintf(el->el_errfile, "edit: Bad value `" FSTR "'.\n",
631                     how);
632                 return -1;
633         }
634         return 0;
635 }