GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libedit/parse.c Lines: 22 96 22.9 %
Date: 2017-11-07 Branches: 10 77 13.0 %

Line Branch Exec Source
1
/*	$OpenBSD: parse.c,v 1.20 2016/04/11 21:17:29 schwarze Exp $	*/
2
/*	$NetBSD: parse.c,v 1.38 2016/04/11 18:56:31 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
 * parse.c: parse an editline extended command
40
 *
41
 * commands are:
42
 *
43
 *	bind
44
 *	echotc
45
 *	edit
46
 *	gettc
47
 *	history
48
 *	settc
49
 *	setty
50
 */
51
#include <stdlib.h>
52
#include <string.h>
53
54
#include "el.h"
55
#include "parse.h"
56
57
static const struct {
58
	const wchar_t *name;
59
	int (*func)(EditLine *, int, const wchar_t **);
60
} cmds[] = {
61
	{ L"bind",		map_bind	},
62
	{ L"echotc",		terminal_echotc	},
63
	{ L"edit",		el_editmode	},
64
	{ L"history",		hist_command	},
65
	{ L"telltc",		terminal_telltc	},
66
	{ L"settc",		terminal_settc	},
67
	{ L"setty",		tty_stty	},
68
	{ NULL,			NULL		}
69
};
70
71
72
/* parse_line():
73
 *	Parse a line and dispatch it
74
 */
75
protected int
76
parse_line(EditLine *el, const wchar_t *line)
77
{
78
	const wchar_t **argv;
79
	int argc;
80
	TokenizerW *tok;
81
82
	tok = tok_winit(NULL);
83
	tok_wstr(tok, line, &argc, &argv);
84
	argc = el_wparse(el, argc, argv);
85
	tok_wend(tok);
86
	return argc;
87
}
88
89
90
/* el_parse():
91
 *	Command dispatcher
92
 */
93
int
94
el_wparse(EditLine *el, int argc, const wchar_t *argv[])
95
{
96
	const wchar_t *ptr;
97
	int i;
98
99
	if (argc < 1)
100
		return -1;
101
	ptr = wcschr(argv[0], L':');
102
	if (ptr != NULL) {
103
		wchar_t *tprog;
104
		size_t l;
105
106
		if (ptr == argv[0])
107
			return 0;
108
		l = ptr - argv[0] - 1;
109
		tprog = reallocarray(NULL, l + 1, sizeof(*tprog));
110
		if (tprog == NULL)
111
			return 0;
112
		(void) wcsncpy(tprog, argv[0], l);
113
		tprog[l] = '\0';
114
		ptr++;
115
		l = el_match(el->el_prog, tprog);
116
		free(tprog);
117
		if (!l)
118
			return 0;
119
	} else
120
		ptr = argv[0];
121
122
	for (i = 0; cmds[i].name != NULL; i++)
123
		if (wcscmp(cmds[i].name, ptr) == 0) {
124
			i = (*cmds[i].func) (el, argc, argv);
125
			return -i;
126
		}
127
	return -1;
128
}
129
130
131
/* parse__escape():
132
 *	Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return
133
 *	the appropriate character or -1 if the escape is not valid
134
 */
135
protected int
136
parse__escape(const wchar_t **ptr)
137
{
138
	const wchar_t *p;
139
	wint_t c;
140
141
24
	p = *ptr;
142
143
12
	if (p[1] == 0)
144
		return -1;
145
146
12
	if (*p == '\\') {
147
		p++;
148
		switch (*p) {
149
		case 'a':
150
			c = '\007';	/* Bell */
151
			break;
152
		case 'b':
153
			c = '\010';	/* Backspace */
154
			break;
155
		case 't':
156
			c = '\011';	/* Horizontal Tab */
157
			break;
158
		case 'n':
159
			c = '\012';	/* New Line */
160
			break;
161
		case 'v':
162
			c = '\013';	/* Vertical Tab */
163
			break;
164
		case 'f':
165
			c = '\014';	/* Form Feed */
166
			break;
167
		case 'r':
168
			c = '\015';	/* Carriage Return */
169
			break;
170
		case 'e':
171
			c = '\033';	/* Escape */
172
			break;
173
		case 'U':		/* Unicode \U+xxxx or \U+xxxxx format */
174
		{
175
			int i;
176
			const wchar_t hex[] = L"0123456789ABCDEF";
177
			const wchar_t *h;
178
			++p;
179
			if (*p++ != '+')
180
				return -1;
181
			c = 0;
182
			for (i = 0; i < 5; ++i) {
183
				h = wcschr(hex, *p++);
184
				if (!h && i < 4)
185
					return -1;
186
				else if (h)
187
					c = (c << 4) | ((int)(h - hex));
188
				else
189
					--p;
190
			}
191
			if (c > 0x10FFFF) /* outside valid character range */
192
				return -1;
193
			break;
194
		}
195
		case '0':
196
		case '1':
197
		case '2':
198
		case '3':
199
		case '4':
200
		case '5':
201
		case '6':
202
		case '7':
203
		{
204
			int cnt, ch;
205
206
			for (cnt = 0, c = 0; cnt < 3; cnt++) {
207
				ch = *p++;
208
				if (ch < '0' || ch > '7') {
209
					p--;
210
					break;
211
				}
212
				c = (c << 3) | (ch - '0');
213
			}
214
			if ((c & 0xffffff00) != 0)
215
				return -1;
216
			--p;
217
			break;
218
		}
219
		default:
220
			c = *p;
221
			break;
222
		}
223
12
	} else if (*p == '^') {
224
12
		p++;
225
36
		c = (*p == '?') ? '\177' : (*p & 0237);
226
12
	} else
227
		c = *p;
228
12
	*ptr = ++p;
229
12
	return c;
230
12
}
231
232
/* parse__string():
233
 *	Parse the escapes from in and put the raw string out
234
 */
235
protected wchar_t *
236
parse__string(wchar_t *out, const wchar_t *in)
237
{
238
	wchar_t *rv = out;
239
	int n;
240
241
12
	for (;;)
242

24
		switch (*in) {
243
		case '\0':
244
12
			*out = '\0';
245
12
			return rv;
246
247
		case '\\':
248
		case '^':
249
12
			if ((n = parse__escape(&in)) == -1)
250
				return NULL;
251
12
			*out++ = (wchar_t)n;
252
12
			break;
253
254
		case 'M':
255
			if (in[1] == '-' && in[2] != '\0') {
256
				*out++ = '\033';
257
				in += 2;
258
				break;
259
			}
260
			/*FALLTHROUGH*/
261
262
		default:
263
			*out++ = *in++;
264
			break;
265
		}
266
12
}
267
268
269
/* parse_cmd():
270
 *	Return the command number for the command string given
271
 *	or -1 if one is not found
272
 */
273
protected int
274
parse_cmd(EditLine *el, const wchar_t *cmd)
275
{
276
	el_bindings_t *b;
277
	int i;
278
279
2352
	for (b = el->el_map.help, i = 0; i < el->el_map.nfunc; i++)
280
1170
		if (wcscmp(b[i].name, cmd) == 0)
281
12
			return b[i].func;
282
	return -1;
283
12
}