xref: /freebsd/contrib/libedit/parse.c (revision 61c1328eb016476ee7ff5ad65d8224bb43e572db)
1*d0ef721eSBaptiste Daroussin /*	$NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 christos Exp $	*/
2*d0ef721eSBaptiste Daroussin 
3*d0ef721eSBaptiste Daroussin /*-
4*d0ef721eSBaptiste Daroussin  * Copyright (c) 1992, 1993
5*d0ef721eSBaptiste Daroussin  *	The Regents of the University of California.  All rights reserved.
6*d0ef721eSBaptiste Daroussin  *
7*d0ef721eSBaptiste Daroussin  * This code is derived from software contributed to Berkeley by
8*d0ef721eSBaptiste Daroussin  * Christos Zoulas of Cornell University.
9*d0ef721eSBaptiste Daroussin  *
10*d0ef721eSBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
11*d0ef721eSBaptiste Daroussin  * modification, are permitted provided that the following conditions
12*d0ef721eSBaptiste Daroussin  * are met:
13*d0ef721eSBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
14*d0ef721eSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
15*d0ef721eSBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
16*d0ef721eSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
17*d0ef721eSBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
18*d0ef721eSBaptiste Daroussin  * 3. Neither the name of the University nor the names of its contributors
19*d0ef721eSBaptiste Daroussin  *    may be used to endorse or promote products derived from this software
20*d0ef721eSBaptiste Daroussin  *    without specific prior written permission.
21*d0ef721eSBaptiste Daroussin  *
22*d0ef721eSBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23*d0ef721eSBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*d0ef721eSBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*d0ef721eSBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*d0ef721eSBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*d0ef721eSBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*d0ef721eSBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*d0ef721eSBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*d0ef721eSBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*d0ef721eSBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*d0ef721eSBaptiste Daroussin  * SUCH DAMAGE.
33*d0ef721eSBaptiste Daroussin  */
34*d0ef721eSBaptiste Daroussin 
35*d0ef721eSBaptiste Daroussin #include "config.h"
36*d0ef721eSBaptiste Daroussin #if !defined(lint) && !defined(SCCSID)
37*d0ef721eSBaptiste Daroussin #if 0
38*d0ef721eSBaptiste Daroussin static char sccsid[] = "@(#)parse.c	8.1 (Berkeley) 6/4/93";
39*d0ef721eSBaptiste Daroussin #else
40*d0ef721eSBaptiste Daroussin __RCSID("$NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 christos Exp $");
41*d0ef721eSBaptiste Daroussin #endif
42*d0ef721eSBaptiste Daroussin #endif /* not lint && not SCCSID */
43*d0ef721eSBaptiste Daroussin 
44*d0ef721eSBaptiste Daroussin /*
45*d0ef721eSBaptiste Daroussin  * parse.c: parse an editline extended command
46*d0ef721eSBaptiste Daroussin  *
47*d0ef721eSBaptiste Daroussin  * commands are:
48*d0ef721eSBaptiste Daroussin  *
49*d0ef721eSBaptiste Daroussin  *	bind
50*d0ef721eSBaptiste Daroussin  *	echotc
51*d0ef721eSBaptiste Daroussin  *	edit
52*d0ef721eSBaptiste Daroussin  *	gettc
53*d0ef721eSBaptiste Daroussin  *	history
54*d0ef721eSBaptiste Daroussin  *	settc
55*d0ef721eSBaptiste Daroussin  *	setty
56*d0ef721eSBaptiste Daroussin  */
57*d0ef721eSBaptiste Daroussin #include <stdlib.h>
58*d0ef721eSBaptiste Daroussin #include <string.h>
59*d0ef721eSBaptiste Daroussin 
60*d0ef721eSBaptiste Daroussin #include "el.h"
61*d0ef721eSBaptiste Daroussin #include "parse.h"
62*d0ef721eSBaptiste Daroussin 
63*d0ef721eSBaptiste Daroussin static const struct {
64*d0ef721eSBaptiste Daroussin 	const wchar_t *name;
65*d0ef721eSBaptiste Daroussin 	int (*func)(EditLine *, int, const wchar_t **);
66*d0ef721eSBaptiste Daroussin } cmds[] = {
67*d0ef721eSBaptiste Daroussin 	{ L"bind",		map_bind	},
68*d0ef721eSBaptiste Daroussin 	{ L"echotc",		terminal_echotc	},
69*d0ef721eSBaptiste Daroussin 	{ L"edit",		el_editmode	},
70*d0ef721eSBaptiste Daroussin 	{ L"history",		hist_command	},
71*d0ef721eSBaptiste Daroussin 	{ L"telltc",		terminal_telltc	},
72*d0ef721eSBaptiste Daroussin 	{ L"settc",		terminal_settc	},
73*d0ef721eSBaptiste Daroussin 	{ L"setty",		tty_stty	},
74*d0ef721eSBaptiste Daroussin 	{ NULL,			NULL		}
75*d0ef721eSBaptiste Daroussin };
76*d0ef721eSBaptiste Daroussin 
77*d0ef721eSBaptiste Daroussin 
78*d0ef721eSBaptiste Daroussin /* parse_line():
79*d0ef721eSBaptiste Daroussin  *	Parse a line and dispatch it
80*d0ef721eSBaptiste Daroussin  */
81*d0ef721eSBaptiste Daroussin libedit_private int
parse_line(EditLine * el,const wchar_t * line)82*d0ef721eSBaptiste Daroussin parse_line(EditLine *el, const wchar_t *line)
83*d0ef721eSBaptiste Daroussin {
84*d0ef721eSBaptiste Daroussin 	const wchar_t **argv;
85*d0ef721eSBaptiste Daroussin 	int argc;
86*d0ef721eSBaptiste Daroussin 	TokenizerW *tok;
87*d0ef721eSBaptiste Daroussin 
88*d0ef721eSBaptiste Daroussin 	tok = tok_winit(NULL);
89*d0ef721eSBaptiste Daroussin 	tok_wstr(tok, line, &argc, &argv);
90*d0ef721eSBaptiste Daroussin 	argc = el_wparse(el, argc, argv);
91*d0ef721eSBaptiste Daroussin 	tok_wend(tok);
92*d0ef721eSBaptiste Daroussin 	return argc;
93*d0ef721eSBaptiste Daroussin }
94*d0ef721eSBaptiste Daroussin 
95*d0ef721eSBaptiste Daroussin 
96*d0ef721eSBaptiste Daroussin /* el_parse():
97*d0ef721eSBaptiste Daroussin  *	Command dispatcher
98*d0ef721eSBaptiste Daroussin  */
99*d0ef721eSBaptiste Daroussin int
el_wparse(EditLine * el,int argc,const wchar_t * argv[])100*d0ef721eSBaptiste Daroussin el_wparse(EditLine *el, int argc, const wchar_t *argv[])
101*d0ef721eSBaptiste Daroussin {
102*d0ef721eSBaptiste Daroussin 	const wchar_t *ptr;
103*d0ef721eSBaptiste Daroussin 	int i;
104*d0ef721eSBaptiste Daroussin 
105*d0ef721eSBaptiste Daroussin 	if (argc < 1)
106*d0ef721eSBaptiste Daroussin 		return -1;
107*d0ef721eSBaptiste Daroussin 	ptr = wcschr(argv[0], L':');
108*d0ef721eSBaptiste Daroussin 	if (ptr != NULL) {
109*d0ef721eSBaptiste Daroussin 		wchar_t *tprog;
110*d0ef721eSBaptiste Daroussin 		size_t l;
111*d0ef721eSBaptiste Daroussin 
112*d0ef721eSBaptiste Daroussin 		if (ptr == argv[0])
113*d0ef721eSBaptiste Daroussin 			return 0;
114*d0ef721eSBaptiste Daroussin 		l = (size_t)(ptr - argv[0]);
115*d0ef721eSBaptiste Daroussin 		tprog = el_calloc(l + 1, sizeof(*tprog));
116*d0ef721eSBaptiste Daroussin 		if (tprog == NULL)
117*d0ef721eSBaptiste Daroussin 			return 0;
118*d0ef721eSBaptiste Daroussin 		(void) wcsncpy(tprog, argv[0], l);
119*d0ef721eSBaptiste Daroussin 		tprog[l] = '\0';
120*d0ef721eSBaptiste Daroussin 		ptr++;
121*d0ef721eSBaptiste Daroussin 		l = (size_t)el_match(el->el_prog, tprog);
122*d0ef721eSBaptiste Daroussin 		el_free(tprog);
123*d0ef721eSBaptiste Daroussin 		if (!l)
124*d0ef721eSBaptiste Daroussin 			return 0;
125*d0ef721eSBaptiste Daroussin 	} else
126*d0ef721eSBaptiste Daroussin 		ptr = argv[0];
127*d0ef721eSBaptiste Daroussin 
128*d0ef721eSBaptiste Daroussin 	for (i = 0; cmds[i].name != NULL; i++)
129*d0ef721eSBaptiste Daroussin 		if (wcscmp(cmds[i].name, ptr) == 0) {
130*d0ef721eSBaptiste Daroussin 			i = (*cmds[i].func) (el, argc, argv);
131*d0ef721eSBaptiste Daroussin 			return -i;
132*d0ef721eSBaptiste Daroussin 		}
133*d0ef721eSBaptiste Daroussin 	return -1;
134*d0ef721eSBaptiste Daroussin }
135*d0ef721eSBaptiste Daroussin 
136*d0ef721eSBaptiste Daroussin 
137*d0ef721eSBaptiste Daroussin /* parse__escape():
138*d0ef721eSBaptiste Daroussin  *	Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return
139*d0ef721eSBaptiste Daroussin  *	the appropriate character or -1 if the escape is not valid
140*d0ef721eSBaptiste Daroussin  */
141*d0ef721eSBaptiste Daroussin libedit_private int
parse__escape(const wchar_t ** ptr)142*d0ef721eSBaptiste Daroussin parse__escape(const wchar_t **ptr)
143*d0ef721eSBaptiste Daroussin {
144*d0ef721eSBaptiste Daroussin 	const wchar_t *p;
145*d0ef721eSBaptiste Daroussin 	wint_t c;
146*d0ef721eSBaptiste Daroussin 
147*d0ef721eSBaptiste Daroussin 	p = *ptr;
148*d0ef721eSBaptiste Daroussin 
149*d0ef721eSBaptiste Daroussin 	if (p[1] == 0)
150*d0ef721eSBaptiste Daroussin 		return -1;
151*d0ef721eSBaptiste Daroussin 
152*d0ef721eSBaptiste Daroussin 	if (*p == '\\') {
153*d0ef721eSBaptiste Daroussin 		p++;
154*d0ef721eSBaptiste Daroussin 		switch (*p) {
155*d0ef721eSBaptiste Daroussin 		case 'a':
156*d0ef721eSBaptiste Daroussin 			c = '\007';	/* Bell */
157*d0ef721eSBaptiste Daroussin 			break;
158*d0ef721eSBaptiste Daroussin 		case 'b':
159*d0ef721eSBaptiste Daroussin 			c = '\010';	/* Backspace */
160*d0ef721eSBaptiste Daroussin 			break;
161*d0ef721eSBaptiste Daroussin 		case 't':
162*d0ef721eSBaptiste Daroussin 			c = '\011';	/* Horizontal Tab */
163*d0ef721eSBaptiste Daroussin 			break;
164*d0ef721eSBaptiste Daroussin 		case 'n':
165*d0ef721eSBaptiste Daroussin 			c = '\012';	/* New Line */
166*d0ef721eSBaptiste Daroussin 			break;
167*d0ef721eSBaptiste Daroussin 		case 'v':
168*d0ef721eSBaptiste Daroussin 			c = '\013';	/* Vertical Tab */
169*d0ef721eSBaptiste Daroussin 			break;
170*d0ef721eSBaptiste Daroussin 		case 'f':
171*d0ef721eSBaptiste Daroussin 			c = '\014';	/* Form Feed */
172*d0ef721eSBaptiste Daroussin 			break;
173*d0ef721eSBaptiste Daroussin 		case 'r':
174*d0ef721eSBaptiste Daroussin 			c = '\015';	/* Carriage Return */
175*d0ef721eSBaptiste Daroussin 			break;
176*d0ef721eSBaptiste Daroussin 		case 'e':
177*d0ef721eSBaptiste Daroussin 			c = '\033';	/* Escape */
178*d0ef721eSBaptiste Daroussin 			break;
179*d0ef721eSBaptiste Daroussin 		case 'U':		/* Unicode \U+xxxx or \U+xxxxx format */
180*d0ef721eSBaptiste Daroussin 		{
181*d0ef721eSBaptiste Daroussin 			int i;
182*d0ef721eSBaptiste Daroussin 			const wchar_t hex[] = L"0123456789ABCDEF";
183*d0ef721eSBaptiste Daroussin 			const wchar_t *h;
184*d0ef721eSBaptiste Daroussin 			++p;
185*d0ef721eSBaptiste Daroussin 			if (*p++ != '+')
186*d0ef721eSBaptiste Daroussin 				return -1;
187*d0ef721eSBaptiste Daroussin 			c = 0;
188*d0ef721eSBaptiste Daroussin 			for (i = 0; i < 5; ++i) {
189*d0ef721eSBaptiste Daroussin 				h = wcschr(hex, *p++);
190*d0ef721eSBaptiste Daroussin 				if (!h && i < 4)
191*d0ef721eSBaptiste Daroussin 					return -1;
192*d0ef721eSBaptiste Daroussin 				else if (h)
193*d0ef721eSBaptiste Daroussin 					c = (c << 4) | ((int)(h - hex));
194*d0ef721eSBaptiste Daroussin 				else
195*d0ef721eSBaptiste Daroussin 					--p;
196*d0ef721eSBaptiste Daroussin 			}
197*d0ef721eSBaptiste Daroussin 			if (c > 0x10FFFF) /* outside valid character range */
198*d0ef721eSBaptiste Daroussin 				return -1;
199*d0ef721eSBaptiste Daroussin 			break;
200*d0ef721eSBaptiste Daroussin 		}
201*d0ef721eSBaptiste Daroussin 		case '0':
202*d0ef721eSBaptiste Daroussin 		case '1':
203*d0ef721eSBaptiste Daroussin 		case '2':
204*d0ef721eSBaptiste Daroussin 		case '3':
205*d0ef721eSBaptiste Daroussin 		case '4':
206*d0ef721eSBaptiste Daroussin 		case '5':
207*d0ef721eSBaptiste Daroussin 		case '6':
208*d0ef721eSBaptiste Daroussin 		case '7':
209*d0ef721eSBaptiste Daroussin 		{
210*d0ef721eSBaptiste Daroussin 			int cnt, ch;
211*d0ef721eSBaptiste Daroussin 
212*d0ef721eSBaptiste Daroussin 			for (cnt = 0, c = 0; cnt < 3; cnt++) {
213*d0ef721eSBaptiste Daroussin 				ch = *p++;
214*d0ef721eSBaptiste Daroussin 				if (ch < '0' || ch > '7') {
215*d0ef721eSBaptiste Daroussin 					p--;
216*d0ef721eSBaptiste Daroussin 					break;
217*d0ef721eSBaptiste Daroussin 				}
218*d0ef721eSBaptiste Daroussin 				c = (c << 3) | (ch - '0');
219*d0ef721eSBaptiste Daroussin 			}
220*d0ef721eSBaptiste Daroussin 			if ((c & (wint_t)0xffffff00) != (wint_t)0)
221*d0ef721eSBaptiste Daroussin 				return -1;
222*d0ef721eSBaptiste Daroussin 			--p;
223*d0ef721eSBaptiste Daroussin 			break;
224*d0ef721eSBaptiste Daroussin 		}
225*d0ef721eSBaptiste Daroussin 		default:
226*d0ef721eSBaptiste Daroussin 			c = *p;
227*d0ef721eSBaptiste Daroussin 			break;
228*d0ef721eSBaptiste Daroussin 		}
229*d0ef721eSBaptiste Daroussin 	} else if (*p == '^') {
230*d0ef721eSBaptiste Daroussin 		p++;
231*d0ef721eSBaptiste Daroussin 		c = (*p == '?') ? '\177' : (*p & 0237);
232*d0ef721eSBaptiste Daroussin 	} else
233*d0ef721eSBaptiste Daroussin 		c = *p;
234*d0ef721eSBaptiste Daroussin 	*ptr = ++p;
235*d0ef721eSBaptiste Daroussin 	return c;
236*d0ef721eSBaptiste Daroussin }
237*d0ef721eSBaptiste Daroussin 
238*d0ef721eSBaptiste Daroussin /* parse__string():
239*d0ef721eSBaptiste Daroussin  *	Parse the escapes from in and put the raw string out
240*d0ef721eSBaptiste Daroussin  */
241*d0ef721eSBaptiste Daroussin libedit_private wchar_t *
parse__string(wchar_t * out,const wchar_t * in)242*d0ef721eSBaptiste Daroussin parse__string(wchar_t *out, const wchar_t *in)
243*d0ef721eSBaptiste Daroussin {
244*d0ef721eSBaptiste Daroussin 	wchar_t *rv = out;
245*d0ef721eSBaptiste Daroussin 	int n;
246*d0ef721eSBaptiste Daroussin 
247*d0ef721eSBaptiste Daroussin 	for (;;)
248*d0ef721eSBaptiste Daroussin 		switch (*in) {
249*d0ef721eSBaptiste Daroussin 		case '\0':
250*d0ef721eSBaptiste Daroussin 			*out = '\0';
251*d0ef721eSBaptiste Daroussin 			return rv;
252*d0ef721eSBaptiste Daroussin 
253*d0ef721eSBaptiste Daroussin 		case '\\':
254*d0ef721eSBaptiste Daroussin 		case '^':
255*d0ef721eSBaptiste Daroussin 			if ((n = parse__escape(&in)) == -1)
256*d0ef721eSBaptiste Daroussin 				return NULL;
257*d0ef721eSBaptiste Daroussin 			*out++ = (wchar_t)n;
258*d0ef721eSBaptiste Daroussin 			break;
259*d0ef721eSBaptiste Daroussin 
260*d0ef721eSBaptiste Daroussin 		case 'M':
261*d0ef721eSBaptiste Daroussin 			if (in[1] == '-' && in[2] != '\0') {
262*d0ef721eSBaptiste Daroussin 				*out++ = '\033';
263*d0ef721eSBaptiste Daroussin 				in += 2;
264*d0ef721eSBaptiste Daroussin 				break;
265*d0ef721eSBaptiste Daroussin 			}
266*d0ef721eSBaptiste Daroussin 			/*FALLTHROUGH*/
267*d0ef721eSBaptiste Daroussin 
268*d0ef721eSBaptiste Daroussin 		default:
269*d0ef721eSBaptiste Daroussin 			*out++ = *in++;
270*d0ef721eSBaptiste Daroussin 			break;
271*d0ef721eSBaptiste Daroussin 		}
272*d0ef721eSBaptiste Daroussin }
273*d0ef721eSBaptiste Daroussin 
274*d0ef721eSBaptiste Daroussin 
275*d0ef721eSBaptiste Daroussin /* parse_cmd():
276*d0ef721eSBaptiste Daroussin  *	Return the command number for the command string given
277*d0ef721eSBaptiste Daroussin  *	or -1 if one is not found
278*d0ef721eSBaptiste Daroussin  */
279*d0ef721eSBaptiste Daroussin libedit_private int
parse_cmd(EditLine * el,const wchar_t * cmd)280*d0ef721eSBaptiste Daroussin parse_cmd(EditLine *el, const wchar_t *cmd)
281*d0ef721eSBaptiste Daroussin {
282*d0ef721eSBaptiste Daroussin 	el_bindings_t *b = el->el_map.help;
283*d0ef721eSBaptiste Daroussin 	size_t i;
284*d0ef721eSBaptiste Daroussin 
285*d0ef721eSBaptiste Daroussin 	for (i = 0; i < el->el_map.nfunc; i++)
286*d0ef721eSBaptiste Daroussin 		if (wcscmp(b[i].name, cmd) == 0)
287*d0ef721eSBaptiste Daroussin 			return b[i].func;
288*d0ef721eSBaptiste Daroussin 	return -1;
289*d0ef721eSBaptiste Daroussin }
290