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