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