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