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