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