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