xref: /openbsd-src/lib/libedit/parse.c (revision ddc81437857133802b1cf7d8d5bf0ff2198b602b)
1*ddc81437Sschwarze /*	$OpenBSD: parse.c,v 1.20 2016/04/11 21:17:29 schwarze Exp $	*/
2*ddc81437Sschwarze /*	$NetBSD: parse.c,v 1.38 2016/04/11 18:56:31 christos Exp $	*/
3babb851aSmillert 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1992, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Christos Zoulas of Cornell University.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
196580fee3Smillert  * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
21df930be7Sderaadt  *    without specific prior written permission.
22df930be7Sderaadt  *
23df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt  * SUCH DAMAGE.
34df930be7Sderaadt  */
35df930be7Sderaadt 
36d484b7d0Sotto #include "config.h"
37df930be7Sderaadt 
38df930be7Sderaadt /*
39df930be7Sderaadt  * parse.c: parse an editline extended command
40df930be7Sderaadt  *
41df930be7Sderaadt  * commands are:
42df930be7Sderaadt  *
43df930be7Sderaadt  *	bind
44df930be7Sderaadt  *	echotc
45d484b7d0Sotto  *	edit
46df930be7Sderaadt  *	gettc
47babb851aSmillert  *	history
48babb851aSmillert  *	settc
49babb851aSmillert  *	setty
50df930be7Sderaadt  */
51d484b7d0Sotto #include <stdlib.h>
527ccfa089Sschwarze #include <string.h>
53df930be7Sderaadt 
545564fb94Sschwarze #include "el.h"
555564fb94Sschwarze #include "parse.h"
565564fb94Sschwarze 
57*ddc81437Sschwarze static const struct {
58e3191321Sschwarze 	const wchar_t *name;
59e3191321Sschwarze 	int (*func)(EditLine *, int, const wchar_t **);
60df930be7Sderaadt } cmds[] = {
615c93237dSschwarze 	{ L"bind",		map_bind	},
625c93237dSschwarze 	{ L"echotc",		terminal_echotc	},
635c93237dSschwarze 	{ L"edit",		el_editmode	},
645c93237dSschwarze 	{ L"history",		hist_command	},
655c93237dSschwarze 	{ L"telltc",		terminal_telltc	},
665c93237dSschwarze 	{ L"settc",		terminal_settc	},
675c93237dSschwarze 	{ L"setty",		tty_stty	},
68df930be7Sderaadt 	{ NULL,			NULL		}
69df930be7Sderaadt };
70df930be7Sderaadt 
71df930be7Sderaadt 
72df930be7Sderaadt /* parse_line():
73df930be7Sderaadt  *	Parse a line and dispatch it
74df930be7Sderaadt  */
75df930be7Sderaadt protected int
parse_line(EditLine * el,const wchar_t * line)76e3191321Sschwarze parse_line(EditLine *el, const wchar_t *line)
77df930be7Sderaadt {
78e3191321Sschwarze 	const wchar_t **argv;
79df930be7Sderaadt 	int argc;
805c93237dSschwarze 	TokenizerW *tok;
81df930be7Sderaadt 
825c93237dSschwarze 	tok = tok_winit(NULL);
835c93237dSschwarze 	tok_wstr(tok, line, &argc, &argv);
845c93237dSschwarze 	argc = el_wparse(el, argc, argv);
855c93237dSschwarze 	tok_wend(tok);
8628d54ee8Sschwarze 	return argc;
87df930be7Sderaadt }
88df930be7Sderaadt 
89d484b7d0Sotto 
90df930be7Sderaadt /* el_parse():
91df930be7Sderaadt  *	Command dispatcher
92df930be7Sderaadt  */
93*ddc81437Sschwarze int
el_wparse(EditLine * el,int argc,const wchar_t * argv[])94e3191321Sschwarze el_wparse(EditLine *el, int argc, const wchar_t *argv[])
95df930be7Sderaadt {
96e3191321Sschwarze 	const wchar_t *ptr;
97df930be7Sderaadt 	int i;
98df930be7Sderaadt 
99babb851aSmillert 	if (argc < 1)
10028d54ee8Sschwarze 		return -1;
1015c93237dSschwarze 	ptr = wcschr(argv[0], L':');
102babb851aSmillert 	if (ptr != NULL) {
103e3191321Sschwarze 		wchar_t *tprog;
104d484b7d0Sotto 		size_t l;
105d484b7d0Sotto 
106d484b7d0Sotto 		if (ptr == argv[0])
10728d54ee8Sschwarze 			return 0;
108d484b7d0Sotto 		l = ptr - argv[0] - 1;
109014b1be8Sderaadt 		tprog = reallocarray(NULL, l + 1, sizeof(*tprog));
110d484b7d0Sotto 		if (tprog == NULL)
11128d54ee8Sschwarze 			return 0;
1125c93237dSschwarze 		(void) wcsncpy(tprog, argv[0], l);
113d484b7d0Sotto 		tprog[l] = '\0';
114d484b7d0Sotto 		ptr++;
115d484b7d0Sotto 		l = el_match(el->el_prog, tprog);
116014b1be8Sderaadt 		free(tprog);
117d484b7d0Sotto 		if (!l)
11828d54ee8Sschwarze 			return 0;
119d484b7d0Sotto 	} else
120df930be7Sderaadt 		ptr = argv[0];
121df930be7Sderaadt 
122df930be7Sderaadt 	for (i = 0; cmds[i].name != NULL; i++)
1235c93237dSschwarze 		if (wcscmp(cmds[i].name, ptr) == 0) {
124df930be7Sderaadt 			i = (*cmds[i].func) (el, argc, argv);
12528d54ee8Sschwarze 			return -i;
126df930be7Sderaadt 		}
12728d54ee8Sschwarze 	return -1;
128df930be7Sderaadt }
129df930be7Sderaadt 
130df930be7Sderaadt 
131df930be7Sderaadt /* parse__escape():
132aed0ee81Snicm  *	Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return
133df930be7Sderaadt  *	the appropriate character or -1 if the escape is not valid
134df930be7Sderaadt  */
135df930be7Sderaadt protected int
parse__escape(const wchar_t ** ptr)136e3191321Sschwarze parse__escape(const wchar_t **ptr)
137df930be7Sderaadt {
138e3191321Sschwarze 	const wchar_t *p;
139b2589f0bSschwarze 	wint_t c;
140df930be7Sderaadt 
141df930be7Sderaadt 	p = *ptr;
142df930be7Sderaadt 
143df930be7Sderaadt 	if (p[1] == 0)
14428d54ee8Sschwarze 		return -1;
145df930be7Sderaadt 
146df930be7Sderaadt 	if (*p == '\\') {
147df930be7Sderaadt 		p++;
148df930be7Sderaadt 		switch (*p) {
149df930be7Sderaadt 		case 'a':
150df930be7Sderaadt 			c = '\007';	/* Bell */
151df930be7Sderaadt 			break;
152df930be7Sderaadt 		case 'b':
153df930be7Sderaadt 			c = '\010';	/* Backspace */
154df930be7Sderaadt 			break;
155df930be7Sderaadt 		case 't':
156df930be7Sderaadt 			c = '\011';	/* Horizontal Tab */
157df930be7Sderaadt 			break;
158df930be7Sderaadt 		case 'n':
159df930be7Sderaadt 			c = '\012';	/* New Line */
160df930be7Sderaadt 			break;
161df930be7Sderaadt 		case 'v':
162df930be7Sderaadt 			c = '\013';	/* Vertical Tab */
163df930be7Sderaadt 			break;
164df930be7Sderaadt 		case 'f':
165df930be7Sderaadt 			c = '\014';	/* Form Feed */
166df930be7Sderaadt 			break;
167df930be7Sderaadt 		case 'r':
168df930be7Sderaadt 			c = '\015';	/* Carriage Return */
169df930be7Sderaadt 			break;
170df930be7Sderaadt 		case 'e':
171df930be7Sderaadt 			c = '\033';	/* Escape */
172df930be7Sderaadt 			break;
173aed0ee81Snicm 		case 'U':		/* Unicode \U+xxxx or \U+xxxxx format */
174aed0ee81Snicm 		{
175aed0ee81Snicm 			int i;
176e3191321Sschwarze 			const wchar_t hex[] = L"0123456789ABCDEF";
177e3191321Sschwarze 			const wchar_t *h;
178aed0ee81Snicm 			++p;
179aed0ee81Snicm 			if (*p++ != '+')
18028d54ee8Sschwarze 				return -1;
181aed0ee81Snicm 			c = 0;
182aed0ee81Snicm 			for (i = 0; i < 5; ++i) {
1835c93237dSschwarze 				h = wcschr(hex, *p++);
184aed0ee81Snicm 				if (!h && i < 4)
18528d54ee8Sschwarze 					return -1;
186aed0ee81Snicm 				else if (h)
187aed0ee81Snicm 					c = (c << 4) | ((int)(h - hex));
188aed0ee81Snicm 				else
189aed0ee81Snicm 					--p;
190aed0ee81Snicm 			}
191aed0ee81Snicm 			if (c > 0x10FFFF) /* outside valid character range */
192aed0ee81Snicm 				return -1;
193aed0ee81Snicm 			break;
194aed0ee81Snicm 		}
195df930be7Sderaadt 		case '0':
196df930be7Sderaadt 		case '1':
197df930be7Sderaadt 		case '2':
198df930be7Sderaadt 		case '3':
199df930be7Sderaadt 		case '4':
200df930be7Sderaadt 		case '5':
201df930be7Sderaadt 		case '6':
202df930be7Sderaadt 		case '7':
203df930be7Sderaadt 		{
204df930be7Sderaadt 			int cnt, ch;
205df930be7Sderaadt 
206df930be7Sderaadt 			for (cnt = 0, c = 0; cnt < 3; cnt++) {
207df930be7Sderaadt 				ch = *p++;
208df930be7Sderaadt 				if (ch < '0' || ch > '7') {
209df930be7Sderaadt 					p--;
210df930be7Sderaadt 					break;
211df930be7Sderaadt 				}
212df930be7Sderaadt 				c = (c << 3) | (ch - '0');
213df930be7Sderaadt 			}
214df930be7Sderaadt 			if ((c & 0xffffff00) != 0)
21528d54ee8Sschwarze 				return -1;
216df930be7Sderaadt 			--p;
217df930be7Sderaadt 			break;
218d484b7d0Sotto 		}
219df930be7Sderaadt 		default:
220df930be7Sderaadt 			c = *p;
221df930be7Sderaadt 			break;
222df930be7Sderaadt 		}
2236e02e073Sotto 	} else if (*p == '^') {
224df930be7Sderaadt 		p++;
225df930be7Sderaadt 		c = (*p == '?') ? '\177' : (*p & 0237);
226d484b7d0Sotto 	} else
227df930be7Sderaadt 		c = *p;
228df930be7Sderaadt 	*ptr = ++p;
22928d54ee8Sschwarze 	return c;
230df930be7Sderaadt }
2316e02e073Sotto 
232df930be7Sderaadt /* parse__string():
233df930be7Sderaadt  *	Parse the escapes from in and put the raw string out
234df930be7Sderaadt  */
235e3191321Sschwarze protected wchar_t *
parse__string(wchar_t * out,const wchar_t * in)236e3191321Sschwarze parse__string(wchar_t *out, const wchar_t *in)
237df930be7Sderaadt {
238e3191321Sschwarze 	wchar_t *rv = out;
239df930be7Sderaadt 	int n;
240d484b7d0Sotto 
241df930be7Sderaadt 	for (;;)
242df930be7Sderaadt 		switch (*in) {
243df930be7Sderaadt 		case '\0':
244df930be7Sderaadt 			*out = '\0';
24528d54ee8Sschwarze 			return rv;
246df930be7Sderaadt 
247df930be7Sderaadt 		case '\\':
248df930be7Sderaadt 		case '^':
249df930be7Sderaadt 			if ((n = parse__escape(&in)) == -1)
25028d54ee8Sschwarze 				return NULL;
251e3191321Sschwarze 			*out++ = (wchar_t)n;
252df930be7Sderaadt 			break;
253df930be7Sderaadt 
2546e02e073Sotto 		case 'M':
2556e02e073Sotto 			if (in[1] == '-' && in[2] != '\0') {
2566e02e073Sotto 				*out++ = '\033';
2576e02e073Sotto 				in += 2;
2586e02e073Sotto 				break;
2596e02e073Sotto 			}
2606e02e073Sotto 			/*FALLTHROUGH*/
2616e02e073Sotto 
262df930be7Sderaadt 		default:
263df930be7Sderaadt 			*out++ = *in++;
264df930be7Sderaadt 			break;
265df930be7Sderaadt 		}
266df930be7Sderaadt }
267df930be7Sderaadt 
268d484b7d0Sotto 
269df930be7Sderaadt /* parse_cmd():
270df930be7Sderaadt  *	Return the command number for the command string given
271df930be7Sderaadt  *	or -1 if one is not found
272df930be7Sderaadt  */
273df930be7Sderaadt protected int
parse_cmd(EditLine * el,const wchar_t * cmd)274e3191321Sschwarze parse_cmd(EditLine *el, const wchar_t *cmd)
275df930be7Sderaadt {
276df930be7Sderaadt 	el_bindings_t *b;
27717bf7f0eSpascal 	int i;
278df930be7Sderaadt 
27917bf7f0eSpascal 	for (b = el->el_map.help, i = 0; i < el->el_map.nfunc; i++)
2805c93237dSschwarze 		if (wcscmp(b[i].name, cmd) == 0)
28128d54ee8Sschwarze 			return b[i].func;
28228d54ee8Sschwarze 	return -1;
283df930be7Sderaadt }
284