GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libedit/el.c Lines: 63 252 25.0 %
Date: 2017-11-13 Branches: 26 215 12.1 %

Line Branch Exec Source
1
/*	$OpenBSD: el.c,v 1.37 2017/04/12 18:24:37 tb Exp $	*/
2
/*	$NetBSD: el.c,v 1.61 2011/01/27 23:11:40 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 "config.h"
37
38
/*
39
 * el.c: EditLine interface functions
40
 */
41
#include <sys/types.h>
42
#include <ctype.h>
43
#include <langinfo.h>
44
#include <limits.h>
45
#include <locale.h>
46
#include <stdarg.h>
47
#include <stdlib.h>
48
#include <string.h>
49
50
#include "el.h"
51
#include "parse.h"
52
#include "read.h"
53
54
/* el_init():
55
 *	Initialize editline and set default parameters.
56
 */
57
EditLine *
58
el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
59
{
60
6
	EditLine *el = (EditLine *) calloc(1, sizeof(EditLine));
61
62
3
	if (el == NULL)
63
		return NULL;
64
65
3
	el->el_infile = fin;
66
3
	el->el_outfile = fout;
67
3
	el->el_errfile = ferr;
68
69
9
	el->el_infd = fileno(fin);
70
9
	el->el_outfd = fileno(fout);
71
9
	el->el_errfd = fileno(ferr);
72
73
3
	el->el_prog = wcsdup(ct_decode_string(prog, &el->el_scratch));
74
3
	if (el->el_prog == NULL) {
75
		free(el);
76
		return NULL;
77
	}
78
79
	/*
80
         * Initialize all the modules. Order is important!!!
81
         */
82
3
	el->el_flags = 0;
83
3
	if (setlocale(LC_CTYPE, NULL) != NULL){
84
3
		if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
85
			el->el_flags |= CHARSET_IS_UTF8;
86
	}
87
88
3
	if (terminal_init(el) == -1) {
89
		free(el->el_prog);
90
		free(el);
91
		return NULL;
92
	}
93
3
	(void) keymacro_init(el);
94
3
	(void) map_init(el);
95
3
	if (tty_init(el) == -1)
96
1
		el->el_flags |= NO_TTY;
97
3
	(void) ch_init(el);
98
3
	(void) search_init(el);
99
3
	(void) hist_init(el);
100
3
	(void) prompt_init(el);
101
3
	(void) sig_init(el);
102
3
	if (read_init(el) == -1) {
103
		el_end(el);
104
		return NULL;
105
	}
106
3
	return el;
107
3
}
108
109
110
/* el_end():
111
 *	Clean up.
112
 */
113
void
114
el_end(EditLine *el)
115
{
116
117
	if (el == NULL)
118
		return;
119
120
	el_reset(el);
121
122
	terminal_end(el);
123
	keymacro_end(el);
124
	map_end(el);
125
	tty_end(el);
126
	ch_end(el);
127
	read_end(el->el_read);
128
	search_end(el);
129
	hist_end(el);
130
	prompt_end(el);
131
	sig_end(el);
132
133
	free(el->el_prog);
134
	free(el->el_scratch.cbuff);
135
	free(el->el_scratch.wbuff);
136
	free(el->el_lgcyconv.cbuff);
137
	free(el->el_lgcyconv.wbuff);
138
	free(el);
139
}
140
141
142
/* el_reset():
143
 *	Reset the tty and the parser
144
 */
145
void
146
el_reset(EditLine *el)
147
{
148
149
	tty_cookedmode(el);
150
	ch_reset(el);		/* XXX: Do we want that? */
151
}
152
153
154
/* el_set():
155
 *	set the editline parameters
156
 */
157
int
158
el_wset(EditLine *el, int op, ...)
159
{
160
12
	va_list ap;
161
	int rv = 0;
162
163
6
	if (el == NULL)
164
		return -1;
165
6
	va_start(ap, op);
166
167





6
	switch (op) {
168
	case EL_PROMPT:
169
	case EL_RPROMPT: {
170
		el_pfunc_t p = va_arg(ap, el_pfunc_t);
171
172
		rv = prompt_set(el, p, 0, op, 1);
173
		break;
174
	}
175
176
	case EL_RESIZE: {
177
		el_zfunc_t p = va_arg(ap, el_zfunc_t);
178
		void *arg = va_arg(ap, void *);
179
		rv = ch_resizefun(el, p, arg);
180
		break;
181
	}
182
183
	case EL_PROMPT_ESC:
184
	case EL_RPROMPT_ESC: {
185
		el_pfunc_t p = va_arg(ap, el_pfunc_t);
186
		int c = va_arg(ap, int);
187
188
		rv = prompt_set(el, p, c, op, 1);
189
		break;
190
	}
191
192
	case EL_TERMINAL:
193
		rv = terminal_set(el, va_arg(ap, char *));
194
		break;
195
196
	case EL_EDITOR:
197
9
		rv = map_set_editor(el, va_arg(ap, wchar_t *));
198
3
		break;
199
200
	case EL_SIGNAL:
201
12
		if (va_arg(ap, int))
202
3
			el->el_flags |= HANDLE_SIGNALS;
203
		else
204
3
			el->el_flags &= ~HANDLE_SIGNALS;
205
3
		break;
206
207
	case EL_BIND:
208
	case EL_TELLTC:
209
	case EL_SETTC:
210
	case EL_ECHOTC:
211
	case EL_SETTY:
212
	{
213
		const wchar_t *argv[20];
214
		int i;
215
216
		for (i = 1; i < 20; i++)
217
			if ((argv[i] = va_arg(ap, wchar_t *)) == NULL)
218
				break;
219
220
		switch (op) {
221
		case EL_BIND:
222
			argv[0] = L"bind";
223
			rv = map_bind(el, i, argv);
224
			break;
225
226
		case EL_TELLTC:
227
			argv[0] = L"telltc";
228
			rv = terminal_telltc(el, i, argv);
229
			break;
230
231
		case EL_SETTC:
232
			argv[0] = L"settc";
233
			rv = terminal_settc(el, i, argv);
234
			break;
235
236
		case EL_ECHOTC:
237
			argv[0] = L"echotc";
238
			rv = terminal_echotc(el, i, argv);
239
			break;
240
241
		case EL_SETTY:
242
			argv[0] = L"setty";
243
			rv = tty_stty(el, i, argv);
244
			break;
245
246
		default:
247
			rv = -1;
248
			EL_ABORT((el->el_errfile, "Bad op %d\n", op));
249
			break;
250
		}
251
		break;
252
	}
253
254
	case EL_ADDFN:
255
	{
256
		wchar_t *name = va_arg(ap, wchar_t *);
257
		wchar_t *help = va_arg(ap, wchar_t *);
258
		el_func_t func = va_arg(ap, el_func_t);
259
260
		rv = map_addfunc(el, name, help, func);
261
		break;
262
	}
263
264
	case EL_HIST:
265
	{
266
		hist_fun_t func = va_arg(ap, hist_fun_t);
267
		void *ptr = va_arg(ap, void *);
268
269
		rv = hist_set(el, func, ptr);
270
		if (!(el->el_flags & CHARSET_IS_UTF8))
271
			el->el_flags &= ~NARROW_HISTORY;
272
		break;
273
	}
274
275
	case EL_EDITMODE:
276
		if (va_arg(ap, int))
277
			el->el_flags &= ~EDIT_DISABLED;
278
		else
279
			el->el_flags |= EDIT_DISABLED;
280
		rv = 0;
281
		break;
282
283
	case EL_GETCFN:
284
	{
285
		el_rfunc_t rc = va_arg(ap, el_rfunc_t);
286
		rv = el_read_setfn(el->el_read, rc);
287
		break;
288
	}
289
290
	case EL_CLIENTDATA:
291
		el->el_data = va_arg(ap, void *);
292
		break;
293
294
	case EL_UNBUFFERED:
295
		rv = va_arg(ap, int);
296
		if (rv && !(el->el_flags & UNBUFFERED)) {
297
			el->el_flags |= UNBUFFERED;
298
			read_prepare(el);
299
		} else if (!rv && (el->el_flags & UNBUFFERED)) {
300
			el->el_flags &= ~UNBUFFERED;
301
			read_finish(el);
302
		}
303
		rv = 0;
304
		break;
305
306
	case EL_PREP_TERM:
307
		rv = va_arg(ap, int);
308
		if (rv)
309
			(void) tty_rawmode(el);
310
		else
311
			(void) tty_cookedmode(el);
312
		rv = 0;
313
		break;
314
315
	case EL_SETFP:
316
	{
317
		FILE *fp;
318
		int what;
319
320
		what = va_arg(ap, int);
321
		fp = va_arg(ap, FILE *);
322
323
		rv = 0;
324
		switch (what) {
325
		case 0:
326
			el->el_infile = fp;
327
			el->el_infd = fileno(fp);
328
			break;
329
		case 1:
330
			el->el_outfile = fp;
331
			el->el_outfd = fileno(fp);
332
			break;
333
		case 2:
334
			el->el_errfile = fp;
335
			el->el_errfd = fileno(fp);
336
			break;
337
		default:
338
			rv = -1;
339
			break;
340
		}
341
		break;
342
	}
343
344
	case EL_REFRESH:
345
		re_clear_display(el);
346
		re_refresh(el);
347
		terminal__flush(el);
348
		break;
349
350
	default:
351
		rv = -1;
352
		break;
353
	}
354
355
6
	va_end(ap);
356
6
	return rv;
357
6
}
358
359
360
/* el_get():
361
 *	retrieve the editline parameters
362
 */
363
int
364
el_wget(EditLine *el, int op, ...)
365
{
366
6
	va_list ap;
367
	int rv;
368
369
3
	if (el == NULL)
370
		return -1;
371
372
3
	va_start(ap, op);
373
374



3
	switch (op) {
375
	case EL_PROMPT:
376
	case EL_RPROMPT: {
377
		el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
378
		rv = prompt_get(el, p, 0, op);
379
		break;
380
	}
381
	case EL_PROMPT_ESC:
382
	case EL_RPROMPT_ESC: {
383
		el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
384
		wchar_t *c = va_arg(ap, wchar_t *);
385
386
		rv = prompt_get(el, p, c, op);
387
		break;
388
	}
389
390
	case EL_EDITOR:
391
		rv = map_get_editor(el, va_arg(ap, const wchar_t **));
392
		break;
393
394
	case EL_SIGNAL:
395
		*va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
396
		rv = 0;
397
		break;
398
399
	case EL_EDITMODE:
400
		*va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
401
		rv = 0;
402
		break;
403
404
	case EL_TERMINAL:
405
9
		terminal_get(el, va_arg(ap, const char **));
406
		rv = 0;
407
3
		break;
408
409
	case EL_GETTC:
410
	{
411
		static char name[] = "gettc";
412
		char *argv[20];
413
		int i;
414
415
		for (i = 1; i < (int)(sizeof(argv) / sizeof(argv[0])); i++)
416
			if ((argv[i] = va_arg(ap, char *)) == NULL)
417
				break;
418
419
		switch (op) {
420
		case EL_GETTC:
421
			argv[0] = name;
422
			rv = terminal_gettc(el, i, argv);
423
			break;
424
425
		default:
426
			rv = -1;
427
			EL_ABORT((el->el_errfile, "Bad op %d\n", op));
428
			break;
429
		}
430
		break;
431
	}
432
433
	case EL_GETCFN:
434
		*va_arg(ap, el_rfunc_t *) = el_read_getfn(el->el_read);
435
		rv = 0;
436
		break;
437
438
	case EL_CLIENTDATA:
439
		*va_arg(ap, void **) = el->el_data;
440
		rv = 0;
441
		break;
442
443
	case EL_UNBUFFERED:
444
		*va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED));
445
		rv = 0;
446
		break;
447
448
	case EL_GETFP:
449
	{
450
		int what;
451
		FILE **fpp;
452
453
		what = va_arg(ap, int);
454
		fpp = va_arg(ap, FILE **);
455
		rv = 0;
456
		switch (what) {
457
		case 0:
458
			*fpp = el->el_infile;
459
			break;
460
		case 1:
461
			*fpp = el->el_outfile;
462
			break;
463
		case 2:
464
			*fpp = el->el_errfile;
465
			break;
466
		default:
467
			rv = -1;
468
			break;
469
		}
470
		break;
471
	}
472
	default:
473
		rv = -1;
474
		break;
475
	}
476
3
	va_end(ap);
477
478
3
	return rv;
479
3
}
480
481
482
/* el_line():
483
 *	Return editing info
484
 */
485
const LineInfoW *
486
el_wline(EditLine *el)
487
{
488
489
12
	return (const LineInfoW *)(void *)&el->el_line;
490
}
491
492
493
/* el_source():
494
 *	Source a file
495
 */
496
int
497
el_source(EditLine *el, const char *fname)
498
{
499
	FILE *fp;
500
6
	size_t len;
501
	ssize_t slen;
502
3
	char *ptr;
503
#ifdef HAVE_ISSETUGID
504
3
	char path[PATH_MAX];
505
#endif
506
	const wchar_t *dptr;
507
508
	fp = NULL;
509
3
	if (fname == NULL) {
510
#ifdef HAVE_ISSETUGID
511
		static const char elpath[] = "/.editrc";
512
513
3
		if (issetugid())
514
			return -1;
515
3
		if ((ptr = getenv("HOME")) == NULL)
516
			return -1;
517
3
		if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
518
			return -1;
519
3
		if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
520
			return -1;
521
		fname = path;
522
#else
523
		/*
524
		 * If issetugid() is missing, always return an error, in order
525
		 * to keep from inadvertently opening up the user to a security
526
		 * hole.
527
		 */
528
		return -1;
529
#endif
530
3
	}
531
3
	if (fp == NULL)
532
3
		fp = fopen(fname, "r");
533
3
	if (fp == NULL)
534
3
		return -1;
535
536
	ptr = NULL;
537
	len = 0;
538
	while ((slen = getline(&ptr, &len, fp)) != -1) {
539
		if (*ptr == '\n')
540
			continue;	/* Empty line. */
541
		if (slen > 0 && ptr[--slen] == '\n')
542
			ptr[slen] = '\0';
543
544
		dptr = ct_decode_string(ptr, &el->el_scratch);
545
		if (!dptr)
546
			continue;
547
		/* loop until first non-space char or EOL */
548
		while (*dptr != '\0' && iswspace(*dptr))
549
			dptr++;
550
		if (*dptr == '#')
551
			continue;   /* ignore, this is a comment line */
552
		if (parse_line(el, dptr) == -1) {
553
			free(ptr);
554
			(void) fclose(fp);
555
			return -1;
556
		}
557
	}
558
	free(ptr);
559
	(void) fclose(fp);
560
	return 0;
561
3
}
562
563
564
/* el_resize():
565
 *	Called from program when terminal is resized
566
 */
567
void
568
el_resize(EditLine *el)
569
{
570
	int lins, cols;
571
	sigset_t oset, nset;
572
573
	(void) sigemptyset(&nset);
574
	(void) sigaddset(&nset, SIGWINCH);
575
	(void) sigprocmask(SIG_BLOCK, &nset, &oset);
576
577
	/* get the correct window size */
578
	if (terminal_get_size(el, &lins, &cols))
579
		terminal_change_size(el, lins, cols);
580
581
	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
582
}
583
584
585
/* el_beep():
586
 *	Called from the program to beep
587
 */
588
void
589
el_beep(EditLine *el)
590
{
591
592
	terminal_beep(el);
593
}
594
595
596
/* el_editmode()
597
 *	Set the state of EDIT_DISABLED from the `edit' command.
598
 */
599
protected int
600
/*ARGSUSED*/
601
el_editmode(EditLine *el, int argc, const wchar_t **argv)
602
{
603
	const wchar_t *how;
604
605
	if (argv == NULL || argc != 2 || argv[1] == NULL)
606
		return -1;
607
608
	how = argv[1];
609
	if (wcscmp(how, L"on") == 0) {
610
		el->el_flags &= ~EDIT_DISABLED;
611
		tty_rawmode(el);
612
	} else if (wcscmp(how, L"off") == 0) {
613
		tty_cookedmode(el);
614
		el->el_flags |= EDIT_DISABLED;
615
	}
616
	else {
617
		(void) fprintf(el->el_errfile, "edit: Bad value `%ls'.\n",
618
		    how);
619
		return -1;
620
	}
621
	return 0;
622
}