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