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