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