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