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