1 /* $NetBSD: el.c,v 1.26 2001/11/08 19:34:41 mycroft 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. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if !defined(lint) && !defined(SCCSID) 41 #if 0 42 static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; 43 #else 44 __RCSID("$NetBSD: el.c,v 1.26 2001/11/08 19:34:41 mycroft Exp $"); 45 #endif 46 #endif /* not lint && not SCCSID */ 47 48 /* 49 * el.c: EditLine interface functions 50 */ 51 #include "sys.h" 52 53 #include <sys/types.h> 54 #include <sys/param.h> 55 #include <string.h> 56 #include <stdlib.h> 57 #include <stdarg.h> 58 #include "el.h" 59 60 /* el_init(): 61 * Initialize editline and set default parameters. 62 */ 63 public EditLine * 64 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) 65 { 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_infd = fileno(fin); 75 el->el_outfile = fout; 76 el->el_errfile = ferr; 77 el->el_prog = strdup(prog); 78 79 /* 80 * Initialize all the modules. Order is important!!! 81 */ 82 el->el_flags = 0; 83 84 if (term_init(el) == -1) { 85 free(el->el_prog); 86 el_free(el); 87 return NULL; 88 } 89 (void) key_init(el); 90 (void) map_init(el); 91 if (tty_init(el) == -1) 92 el->el_flags |= NO_TTY; 93 (void) ch_init(el); 94 (void) search_init(el); 95 (void) hist_init(el); 96 (void) prompt_init(el); 97 (void) sig_init(el); 98 (void) read_init(el); 99 100 return (el); 101 } 102 103 104 /* el_end(): 105 * Clean up. 106 */ 107 public void 108 el_end(EditLine *el) 109 { 110 111 if (el == NULL) 112 return; 113 114 el_reset(el); 115 116 term_end(el); 117 key_end(el); 118 map_end(el); 119 tty_end(el); 120 ch_end(el); 121 search_end(el); 122 hist_end(el); 123 prompt_end(el); 124 sig_end(el); 125 126 el_free((ptr_t) el->el_prog); 127 el_free((ptr_t) el); 128 } 129 130 131 /* el_reset(): 132 * Reset the tty and the parser 133 */ 134 public void 135 el_reset(EditLine *el) 136 { 137 138 tty_cookedmode(el); 139 ch_reset(el); /* XXX: Do we want that? */ 140 } 141 142 143 /* el_set(): 144 * set the editline parameters 145 */ 146 public int 147 el_set(EditLine *el, int op, ...) 148 { 149 va_list va; 150 int rv; 151 152 if (el == NULL) 153 return (-1); 154 va_start(va, op); 155 156 switch (op) { 157 case EL_PROMPT: 158 case EL_RPROMPT: 159 rv = prompt_set(el, va_arg(va, el_pfunc_t), op); 160 break; 161 162 case EL_TERMINAL: 163 rv = term_set(el, va_arg(va, char *)); 164 break; 165 166 case EL_EDITOR: 167 rv = map_set_editor(el, va_arg(va, char *)); 168 break; 169 170 case EL_SIGNAL: 171 if (va_arg(va, int)) 172 el->el_flags |= HANDLE_SIGNALS; 173 else 174 el->el_flags &= ~HANDLE_SIGNALS; 175 rv = 0; 176 break; 177 178 case EL_BIND: 179 case EL_TELLTC: 180 case EL_SETTC: 181 case EL_ECHOTC: 182 case EL_SETTY: 183 { 184 char *argv[20]; 185 int i; 186 187 for (i = 1; i < 20; i++) 188 if ((argv[i] = va_arg(va, char *)) == NULL) 189 break; 190 191 switch (op) { 192 case EL_BIND: 193 argv[0] = "bind"; 194 rv = map_bind(el, i, argv); 195 break; 196 197 case EL_TELLTC: 198 argv[0] = "telltc"; 199 rv = term_telltc(el, i, argv); 200 break; 201 202 case EL_SETTC: 203 argv[0] = "settc"; 204 rv = term_settc(el, i, argv); 205 break; 206 207 case EL_ECHOTC: 208 argv[0] = "echotc"; 209 rv = term_echotc(el, i, argv); 210 break; 211 212 case EL_SETTY: 213 argv[0] = "setty"; 214 rv = tty_stty(el, i, argv); 215 break; 216 217 default: 218 rv = -1; 219 EL_ABORT((el->el_errfile, "Bad op %d\n", op)); 220 break; 221 } 222 break; 223 } 224 225 case EL_ADDFN: 226 { 227 char *name = va_arg(va, char *); 228 char *help = va_arg(va, char *); 229 el_func_t func = va_arg(va, el_func_t); 230 231 rv = map_addfunc(el, name, help, func); 232 break; 233 } 234 235 case EL_HIST: 236 { 237 hist_fun_t func = va_arg(va, hist_fun_t); 238 ptr_t ptr = va_arg(va, char *); 239 240 rv = hist_set(el, func, ptr); 241 break; 242 } 243 244 case EL_EDITMODE: 245 if (va_arg(va, int)) 246 el->el_flags &= ~EDIT_DISABLED; 247 else 248 el->el_flags |= EDIT_DISABLED; 249 rv = 0; 250 break; 251 252 case EL_GETCFN: 253 { 254 el_rfunc_t rc = va_arg(va, el_rfunc_t); 255 rv = el_read_setfn(el, rc); 256 break; 257 } 258 259 case EL_CLIENTDATA: 260 el->el_data = va_arg(va, void *); 261 break; 262 263 default: 264 rv = -1; 265 } 266 267 va_end(va); 268 return (rv); 269 } 270 271 272 /* el_get(): 273 * retrieve the editline parameters 274 */ 275 public int 276 el_get(EditLine *el, int op, void *ret) 277 { 278 int rv; 279 280 if (el == NULL || ret == NULL) 281 return (-1); 282 switch (op) { 283 case EL_PROMPT: 284 case EL_RPROMPT: 285 rv = prompt_get(el, (el_pfunc_t *) & ret, op); 286 break; 287 288 case EL_EDITOR: 289 rv = map_get_editor(el, (const char **) &ret); 290 break; 291 292 case EL_SIGNAL: 293 *((int *) ret) = (el->el_flags & HANDLE_SIGNALS); 294 rv = 0; 295 break; 296 297 case EL_EDITMODE: 298 *((int *) ret) = (!(el->el_flags & EDIT_DISABLED)); 299 rv = 0; 300 break; 301 302 #if 0 /* XXX */ 303 case EL_TERMINAL: 304 rv = term_get(el, (const char *) &ret); 305 break; 306 307 case EL_BIND: 308 case EL_TELLTC: 309 case EL_SETTC: 310 case EL_ECHOTC: 311 case EL_SETTY: 312 { 313 char *argv[20]; 314 int i; 315 316 for (i = 1; i < 20; i++) 317 if ((argv[i] = va_arg(va, char *)) == NULL) 318 break; 319 320 switch (op) { 321 case EL_BIND: 322 argv[0] = "bind"; 323 rv = map_bind(el, i, argv); 324 break; 325 326 case EL_TELLTC: 327 argv[0] = "telltc"; 328 rv = term_telltc(el, i, argv); 329 break; 330 331 case EL_SETTC: 332 argv[0] = "settc"; 333 rv = term_settc(el, i, argv); 334 break; 335 336 case EL_ECHOTC: 337 argv[0] = "echotc"; 338 rv = term_echotc(el, i, argv); 339 break; 340 341 case EL_SETTY: 342 argv[0] = "setty"; 343 rv = tty_stty(el, i, argv); 344 break; 345 346 default: 347 rv = -1; 348 EL_ABORT((el->errfile, "Bad op %d\n", op)); 349 break; 350 } 351 break; 352 } 353 354 case EL_ADDFN: 355 { 356 char *name = va_arg(va, char *); 357 char *help = va_arg(va, char *); 358 el_func_t func = va_arg(va, el_func_t); 359 360 rv = map_addfunc(el, name, help, func); 361 break; 362 } 363 364 case EL_HIST: 365 { 366 hist_fun_t func = va_arg(va, hist_fun_t); 367 ptr_t ptr = va_arg(va, char *); 368 rv = hist_set(el, func, ptr); 369 } 370 break; 371 #endif /* XXX */ 372 373 case EL_GETCFN: 374 *((el_rfunc_t *)ret) = el_read_getfn(el); 375 rv = 0; 376 break; 377 378 case EL_CLIENTDATA: 379 *((void **)ret) = el->el_data; 380 rv = 0; 381 break; 382 383 default: 384 rv = -1; 385 } 386 387 return (rv); 388 } 389 390 391 /* el_line(): 392 * Return editing info 393 */ 394 public const LineInfo * 395 el_line(EditLine *el) 396 { 397 398 return (const LineInfo *) (void *) &el->el_line; 399 } 400 401 static const char elpath[] = "/.editrc"; 402 403 /* el_source(): 404 * Source a file 405 */ 406 public int 407 el_source(EditLine *el, const char *fname) 408 { 409 FILE *fp; 410 size_t len; 411 char *ptr, path[MAXPATHLEN]; 412 413 fp = NULL; 414 if (fname == NULL) { 415 if (issetugid()) 416 return (-1); 417 if ((ptr = getenv("HOME")) == NULL) 418 return (-1); 419 if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path)) 420 return (-1); 421 if (strlcat(path, elpath, sizeof(path)) >= sizeof(path)) 422 return (-1); 423 fname = path; 424 } 425 if (fp == NULL) 426 fp = fopen(fname, "r"); 427 if (fp == NULL) 428 return (-1); 429 430 while ((ptr = fgetln(fp, &len)) != NULL) { 431 if (len > 0 && ptr[len - 1] == '\n') 432 --len; 433 ptr[len] = '\0'; 434 if (parse_line(el, ptr) == -1) { 435 (void) fclose(fp); 436 return (-1); 437 } 438 } 439 440 (void) fclose(fp); 441 return (0); 442 } 443 444 445 /* el_resize(): 446 * Called from program when terminal is resized 447 */ 448 public void 449 el_resize(EditLine *el) 450 { 451 int lins, cols; 452 sigset_t oset, nset; 453 454 (void) sigemptyset(&nset); 455 (void) sigaddset(&nset, SIGWINCH); 456 (void) sigprocmask(SIG_BLOCK, &nset, &oset); 457 458 /* get the correct window size */ 459 if (term_get_size(el, &lins, &cols)) 460 term_change_size(el, lins, cols); 461 462 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 463 } 464 465 466 /* el_beep(): 467 * Called from the program to beep 468 */ 469 public void 470 el_beep(EditLine *el) 471 { 472 473 term_beep(el); 474 } 475 476 477 /* el_editmode() 478 * Set the state of EDIT_DISABLED from the `edit' command. 479 */ 480 protected int 481 /*ARGSUSED*/ 482 el_editmode(EditLine *el, int argc, char **argv) 483 { 484 const char *how; 485 486 if (argv == NULL || argc != 2 || argv[1] == NULL) 487 return (-1); 488 489 how = argv[1]; 490 if (strcmp(how, "on") == 0) 491 el->el_flags &= ~EDIT_DISABLED; 492 else if (strcmp(how, "off") == 0) 493 el->el_flags |= EDIT_DISABLED; 494 else { 495 (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how); 496 return (-1); 497 } 498 return (0); 499 } 500