Annotation of src/lib/libedit/el.c, Revision 1.82
1.82 ! christos 1: /* $NetBSD: el.c,v 1.81 2016/02/16 19:08:41 christos Exp $ */
1.2 lukem 2:
1.1 cgd 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.
1.32 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 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:
1.29 christos 35: #include "config.h"
1.1 cgd 36: #if !defined(lint) && !defined(SCCSID)
1.2 lukem 37: #if 0
1.1 cgd 38: static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94";
1.2 lukem 39: #else
1.82 ! christos 40: __RCSID("$NetBSD: el.c,v 1.81 2016/02/16 19:08:41 christos Exp $");
1.2 lukem 41: #endif
1.1 cgd 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>
1.82 ! christos 49: #include <ctype.h>
! 50: #include <stdarg.h>
! 51: #include <stdlib.h>
1.1 cgd 52: #include <string.h>
1.75 christos 53: #ifdef WIDECHAR
1.56 christos 54: #include <locale.h>
1.59 christos 55: #include <langinfo.h>
1.75 christos 56: #endif
57:
1.1 cgd 58: #include "el.h"
1.81 christos 59: #include "parse.h"
1.1 cgd 60:
61: /* el_init():
62: * Initialize editline and set default parameters.
63: */
64: public EditLine *
1.19 lukem 65: el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
1.1 cgd 66: {
1.72 christos 67: return el_init_fd(prog, fin, fout, ferr, fileno(fin), fileno(fout),
68: fileno(ferr));
69: }
70:
71: public EditLine *
72: el_init_fd(const char *prog, FILE *fin, FILE *fout, FILE *ferr,
73: int fdin, int fdout, int fderr)
74: {
1.67 christos 75: EditLine *el = el_malloc(sizeof(*el));
1.1 cgd 76:
1.19 lukem 77: if (el == NULL)
1.68 christos 78: return NULL;
1.1 cgd 79:
1.19 lukem 80: memset(el, 0, sizeof(EditLine));
1.1 cgd 81:
1.44 christos 82: el->el_infile = fin;
1.19 lukem 83: el->el_outfile = fout;
84: el->el_errfile = ferr;
1.44 christos 85:
1.72 christos 86: el->el_infd = fdin;
87: el->el_outfd = fdout;
88: el->el_errfd = fderr;
1.44 christos 89:
1.56 christos 90: el->el_prog = Strdup(ct_decode_string(prog, &el->el_scratch));
91: if (el->el_prog == NULL) {
1.36 christos 92: el_free(el);
93: return NULL;
94: }
1.19 lukem 95:
96: /*
97: * Initialize all the modules. Order is important!!!
98: */
99: el->el_flags = 0;
1.59 christos 100: if (setlocale(LC_CTYPE, NULL) != NULL){
101: if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
1.56 christos 102: el->el_flags |= CHARSET_IS_UTF8;
103: }
1.19 lukem 104:
1.64 christos 105: if (terminal_init(el) == -1) {
1.36 christos 106: el_free(el->el_prog);
1.25 christos 107: el_free(el);
108: return NULL;
109: }
1.66 christos 110: (void) keymacro_init(el);
1.19 lukem 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);
1.23 christos 119: (void) read_init(el);
1.1 cgd 120:
1.68 christos 121: return el;
1.19 lukem 122: }
1.1 cgd 123:
124:
125: /* el_end():
126: * Clean up.
127: */
128: public void
1.19 lukem 129: el_end(EditLine *el)
1.1 cgd 130: {
131:
1.19 lukem 132: if (el == NULL)
133: return;
1.1 cgd 134:
1.19 lukem 135: el_reset(el);
136:
1.64 christos 137: terminal_end(el);
1.66 christos 138: keymacro_end(el);
1.19 lukem 139: map_end(el);
1.74 christos 140: if (!(el->el_flags & NO_TTY))
141: tty_end(el);
1.19 lukem 142: ch_end(el);
143: search_end(el);
144: hist_end(el);
145: prompt_end(el);
146: sig_end(el);
147:
1.67 christos 148: el_free(el->el_prog);
1.56 christos 149: #ifdef WIDECHAR
1.67 christos 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);
1.56 christos 154: #endif
1.67 christos 155: el_free(el);
1.19 lukem 156: }
1.1 cgd 157:
158:
159: /* el_reset():
160: * Reset the tty and the parser
161: */
162: public void
1.19 lukem 163: el_reset(EditLine *el)
1.1 cgd 164: {
1.19 lukem 165:
166: tty_cookedmode(el);
1.40 christos 167: ch_reset(el, 0); /* XXX: Do we want that? */
1.1 cgd 168: }
169:
170:
171: /* el_set():
172: * set the editline parameters
173: */
174: public int
1.56 christos 175: FUN(el,set)(EditLine *el, int op, ...)
1.1 cgd 176: {
1.44 christos 177: va_list ap;
1.27 christos 178: int rv = 0;
1.1 cgd 179:
1.19 lukem 180: if (el == NULL)
1.68 christos 181: return -1;
1.44 christos 182: va_start(ap, op);
1.22 wiz 183:
1.19 lukem 184: switch (op) {
185: case EL_PROMPT:
1.51 christos 186: case EL_RPROMPT: {
187: el_pfunc_t p = va_arg(ap, el_pfunc_t);
1.52 christos 188:
1.56 christos 189: rv = prompt_set(el, p, 0, op, 1);
1.52 christos 190: break;
191: }
192:
1.60 christos 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:
1.73 christos 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:
1.52 christos 207: case EL_PROMPT_ESC:
208: case EL_RPROMPT_ESC: {
209: el_pfunc_t p = va_arg(ap, el_pfunc_t);
1.56 christos 210: int c = va_arg(ap, int);
1.51 christos 211:
1.75 christos 212: rv = prompt_set(el, p, (Char)c, op, 1);
1.50 christos 213: break;
1.51 christos 214: }
1.13 simonb 215:
1.19 lukem 216: case EL_TERMINAL:
1.64 christos 217: rv = terminal_set(el, va_arg(ap, char *));
1.19 lukem 218: break;
1.1 cgd 219:
1.19 lukem 220: case EL_EDITOR:
1.56 christos 221: rv = map_set_editor(el, va_arg(ap, Char *));
1.1 cgd 222: break;
223:
1.19 lukem 224: case EL_SIGNAL:
1.44 christos 225: if (va_arg(ap, int))
1.19 lukem 226: el->el_flags |= HANDLE_SIGNALS;
227: else
228: el->el_flags &= ~HANDLE_SIGNALS;
1.1 cgd 229: break;
230:
1.19 lukem 231: case EL_BIND:
232: case EL_TELLTC:
233: case EL_SETTC:
234: case EL_ECHOTC:
235: case EL_SETTY:
236: {
1.56 christos 237: const Char *argv[20];
1.19 lukem 238: int i;
239:
1.70 christos 240: for (i = 1; i < (int)__arraycount(argv); i++)
1.56 christos 241: if ((argv[i] = va_arg(ap, Char *)) == NULL)
1.19 lukem 242: break;
243:
244: switch (op) {
245: case EL_BIND:
1.56 christos 246: argv[0] = STR("bind");
1.19 lukem 247: rv = map_bind(el, i, argv);
248: break;
249:
250: case EL_TELLTC:
1.56 christos 251: argv[0] = STR("telltc");
1.64 christos 252: rv = terminal_telltc(el, i, argv);
1.19 lukem 253: break;
254:
255: case EL_SETTC:
1.56 christos 256: argv[0] = STR("settc");
1.64 christos 257: rv = terminal_settc(el, i, argv);
1.19 lukem 258: break;
259:
260: case EL_ECHOTC:
1.56 christos 261: argv[0] = STR("echotc");
1.64 christos 262: rv = terminal_echotc(el, i, argv);
1.19 lukem 263: break;
264:
265: case EL_SETTY:
1.56 christos 266: argv[0] = STR("setty");
1.19 lukem 267: rv = tty_stty(el, i, argv);
268: break;
269:
270: default:
271: rv = -1;
1.20 christos 272: EL_ABORT((el->el_errfile, "Bad op %d\n", op));
1.19 lukem 273: break;
274: }
1.1 cgd 275: break;
1.19 lukem 276: }
277:
278: case EL_ADDFN:
279: {
1.56 christos 280: Char *name = va_arg(ap, Char *);
281: Char *help = va_arg(ap, Char *);
1.44 christos 282: el_func_t func = va_arg(ap, el_func_t);
1.1 cgd 283:
1.19 lukem 284: rv = map_addfunc(el, name, help, func);
1.1 cgd 285: break;
1.19 lukem 286: }
287:
288: case EL_HIST:
289: {
1.44 christos 290: hist_fun_t func = va_arg(ap, hist_fun_t);
1.67 christos 291: void *ptr = va_arg(ap, void *);
1.1 cgd 292:
1.19 lukem 293: rv = hist_set(el, func, ptr);
1.59 christos 294: if (!(el->el_flags & CHARSET_IS_UTF8))
295: el->el_flags &= ~NARROW_HISTORY;
1.1 cgd 296: break;
1.19 lukem 297: }
1.1 cgd 298:
1.19 lukem 299: case EL_EDITMODE:
1.44 christos 300: if (va_arg(ap, int))
1.19 lukem 301: el->el_flags &= ~EDIT_DISABLED;
302: else
303: el->el_flags |= EDIT_DISABLED;
304: rv = 0;
1.1 cgd 305: break;
1.13 simonb 306:
1.23 christos 307: case EL_GETCFN:
308: {
1.44 christos 309: el_rfunc_t rc = va_arg(ap, el_rfunc_t);
1.23 christos 310: rv = el_read_setfn(el, rc);
1.58 christos 311: el->el_flags &= ~NARROW_READ;
1.23 christos 312: break;
313: }
314:
1.24 christos 315: case EL_CLIENTDATA:
1.44 christos 316: el->el_data = va_arg(ap, void *);
1.24 christos 317: break;
318:
1.34 christos 319: case EL_UNBUFFERED:
1.44 christos 320: rv = va_arg(ap, int);
1.34 christos 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: }
1.35 christos 328: rv = 0;
329: break;
330:
331: case EL_PREP_TERM:
1.44 christos 332: rv = va_arg(ap, int);
1.35 christos 333: if (rv)
1.38 christos 334: (void) tty_rawmode(el);
1.35 christos 335: else
1.38 christos 336: (void) tty_cookedmode(el);
1.34 christos 337: rv = 0;
338: break;
339:
1.44 christos 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;
1.61 christos 356: el->el_outfd = fileno(fp);
1.44 christos 357: break;
358: case 2:
359: el->el_errfile = fp;
1.61 christos 360: el->el_errfd = fileno(fp);
1.44 christos 361: break;
362: default:
363: rv = -1;
364: break;
365: }
366: break;
367: }
368:
1.45 christos 369: case EL_REFRESH:
370: re_clear_display(el);
371: re_refresh(el);
1.64 christos 372: terminal__flush(el);
1.45 christos 373: break;
374:
1.19 lukem 375: default:
376: rv = -1;
1.27 christos 377: break;
1.1 cgd 378: }
379:
1.44 christos 380: va_end(ap);
1.68 christos 381: return rv;
1.19 lukem 382: }
1.1 cgd 383:
384:
1.10 lukem 385: /* el_get():
386: * retrieve the editline parameters
387: */
388: public int
1.56 christos 389: FUN(el,get)(EditLine *el, int op, ...)
1.10 lukem 390: {
1.42 christos 391: va_list ap;
1.19 lukem 392: int rv;
1.10 lukem 393:
1.42 christos 394: if (el == NULL)
395: return -1;
396:
397: va_start(ap, op);
398:
1.19 lukem 399: switch (op) {
400: case EL_PROMPT:
1.51 christos 401: case EL_RPROMPT: {
402: el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
1.56 christos 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 *);
1.51 christos 410:
411: rv = prompt_get(el, p, c, op);
1.19 lukem 412: break;
1.51 christos 413: }
1.10 lukem 414:
1.19 lukem 415: case EL_EDITOR:
1.56 christos 416: rv = map_get_editor(el, va_arg(ap, const Char **));
1.10 lukem 417: break;
418:
1.19 lukem 419: case EL_SIGNAL:
1.42 christos 420: *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
1.19 lukem 421: rv = 0;
1.10 lukem 422: break;
423:
1.19 lukem 424: case EL_EDITMODE:
1.42 christos 425: *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
1.19 lukem 426: rv = 0;
1.10 lukem 427: break;
428:
1.19 lukem 429: case EL_TERMINAL:
1.64 christos 430: terminal_get(el, va_arg(ap, const char **));
1.33 christos 431: rv = 0;
1.10 lukem 432: break;
433:
1.42 christos 434: case EL_GETTC:
1.19 lukem 435: {
1.42 christos 436: static char name[] = "gettc";
437: char *argv[20];
1.19 lukem 438: int i;
1.10 lukem 439:
1.82 ! christos 440: for (i = 1; i < (int)__arraycount(argv); i++)
1.42 christos 441: if ((argv[i] = va_arg(ap, char *)) == NULL)
1.19 lukem 442: break;
443:
1.69 christos 444: argv[0] = name;
445: rv = terminal_gettc(el, i, argv);
1.10 lukem 446: break;
447: }
1.13 simonb 448:
1.23 christos 449: case EL_GETCFN:
1.42 christos 450: *va_arg(ap, el_rfunc_t *) = el_read_getfn(el);
1.24 christos 451: rv = 0;
452: break;
453:
454: case EL_CLIENTDATA:
1.42 christos 455: *va_arg(ap, void **) = el->el_data;
1.34 christos 456: rv = 0;
457: break;
458:
459: case EL_UNBUFFERED:
1.71 christos 460: *va_arg(ap, int *) = (el->el_flags & UNBUFFERED) != 0;
1.23 christos 461: rv = 0;
462: break;
1.19 lukem 463:
1.44 christos 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: }
1.19 lukem 488: default:
489: rv = -1;
1.44 christos 490: break;
1.19 lukem 491: }
1.42 christos 492: va_end(ap);
1.10 lukem 493:
1.68 christos 494: return rv;
1.19 lukem 495: }
1.10 lukem 496:
497:
1.1 cgd 498: /* el_line():
499: * Return editing info
500: */
1.56 christos 501: public const TYPE(LineInfo) *
502: FUN(el,line)(EditLine *el)
1.1 cgd 503: {
1.19 lukem 504:
1.68 christos 505: return (const TYPE(LineInfo) *)(void *)&el->el_line;
1.1 cgd 506: }
507:
508:
509: /* el_source():
510: * Source a file
511: */
512: public int
1.19 lukem 513: el_source(EditLine *el, const char *fname)
1.1 cgd 514: {
1.19 lukem 515: FILE *fp;
516: size_t len;
1.77 christos 517: ssize_t slen;
1.27 christos 518: char *ptr;
1.64 christos 519: char *path = NULL;
1.56 christos 520: const Char *dptr;
1.64 christos 521: int error = 0;
1.19 lukem 522:
523: fp = NULL;
524: if (fname == NULL) {
1.29 christos 525: #ifdef HAVE_ISSETUGID
1.27 christos 526: static const char elpath[] = "/.editrc";
1.65 christos 527: size_t plen = sizeof(elpath);
1.27 christos 528:
1.19 lukem 529: if (issetugid())
1.68 christos 530: return -1;
1.19 lukem 531: if ((ptr = getenv("HOME")) == NULL)
1.68 christos 532: return -1;
1.65 christos 533: plen += strlen(ptr);
1.67 christos 534: if ((path = el_malloc(plen * sizeof(*path))) == NULL)
1.68 christos 535: return -1;
1.65 christos 536: (void)snprintf(path, plen, "%s%s", ptr, elpath);
1.19 lukem 537: fname = path;
1.27 christos 538: #else
539: /*
540: * If issetugid() is missing, always return an error, in order
541: * to keep from inadvertently opening up the user to a security
542: * hole.
543: */
1.68 christos 544: return -1;
1.27 christos 545: #endif
1.19 lukem 546: }
547: if (fp == NULL)
548: fp = fopen(fname, "r");
1.64 christos 549: if (fp == NULL) {
550: el_free(path);
1.68 christos 551: return -1;
1.64 christos 552: }
1.19 lukem 553:
1.77 christos 554: ptr = NULL;
555: len = 0;
556: while ((slen = getline(&ptr, &len, fp)) != -1) {
1.63 christos 557: if (*ptr == '\n')
558: continue; /* Empty line. */
1.77 christos 559: if (slen > 0 && ptr[--slen] == '\n')
560: ptr[slen] = '\0';
561:
1.56 christos 562: dptr = ct_decode_string(ptr, &el->el_scratch);
563: if (!dptr)
564: continue;
1.55 christos 565: /* loop until first non-space char or EOL */
1.56 christos 566: while (*dptr != '\0' && Isspace(*dptr))
567: dptr++;
568: if (*dptr == '#')
1.55 christos 569: continue; /* ignore, this is a comment line */
1.64 christos 570: if ((error = parse_line(el, dptr)) == -1)
571: break;
1.1 cgd 572: }
1.76 christos 573: free(ptr);
1.1 cgd 574:
1.64 christos 575: el_free(path);
1.19 lukem 576: (void) fclose(fp);
1.68 christos 577: return error;
1.1 cgd 578: }
579:
580:
581: /* el_resize():
582: * Called from program when terminal is resized
583: */
584: public void
1.19 lukem 585: el_resize(EditLine *el)
1.1 cgd 586: {
1.19 lukem 587: int lins, cols;
588: sigset_t oset, nset;
589:
590: (void) sigemptyset(&nset);
591: (void) sigaddset(&nset, SIGWINCH);
592: (void) sigprocmask(SIG_BLOCK, &nset, &oset);
593:
594: /* get the correct window size */
1.64 christos 595: if (terminal_get_size(el, &lins, &cols))
596: terminal_change_size(el, lins, cols);
1.1 cgd 597:
1.19 lukem 598: (void) sigprocmask(SIG_SETMASK, &oset, NULL);
1.9 christos 599: }
1.14 lukem 600:
1.9 christos 601:
602: /* el_beep():
603: * Called from the program to beep
604: */
605: public void
1.19 lukem 606: el_beep(EditLine *el)
1.9 christos 607: {
1.19 lukem 608:
1.64 christos 609: terminal_beep(el);
1.1 cgd 610: }
1.10 lukem 611:
612:
613: /* el_editmode()
614: * Set the state of EDIT_DISABLED from the `edit' command.
615: */
616: protected int
617: /*ARGSUSED*/
1.56 christos 618: el_editmode(EditLine *el, int argc, const Char **argv)
1.10 lukem 619: {
1.56 christos 620: const Char *how;
1.10 lukem 621:
1.19 lukem 622: if (argv == NULL || argc != 2 || argv[1] == NULL)
1.68 christos 623: return -1;
1.10 lukem 624:
1.19 lukem 625: how = argv[1];
1.56 christos 626: if (Strcmp(how, STR("on")) == 0) {
1.19 lukem 627: el->el_flags &= ~EDIT_DISABLED;
1.39 christos 628: tty_rawmode(el);
1.56 christos 629: } else if (Strcmp(how, STR("off")) == 0) {
1.39 christos 630: tty_cookedmode(el);
1.19 lukem 631: el->el_flags |= EDIT_DISABLED;
1.39 christos 632: }
1.19 lukem 633: else {
1.56 christos 634: (void) fprintf(el->el_errfile, "edit: Bad value `" FSTR "'.\n",
635: how);
1.68 christos 636: return -1;
1.19 lukem 637: }
1.68 christos 638: return 0;
1.19 lukem 639: }
CVSweb <webmaster@jp.NetBSD.org>