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