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