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