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