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