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