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