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