Merge commit 'dfc115332c94a2f62058ac7f2bce7631fbd20b3d'
[unleashed/tickless.git] / lib / libedit / parse.c
blob3d429ba0ed791265fbb7ec0a7be2a0d86f375a17
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 $ */
4 /*-
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
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.
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.
36 #include "config.h"
39 * parse.c: parse an editline extended command
41 * commands are:
43 * bind
44 * echotc
45 * edit
46 * gettc
47 * history
48 * settc
49 * setty
51 #include <stdlib.h>
52 #include <string.h>
54 #include "el.h"
55 #include "parse.h"
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 }
72 /* parse_line():
73 * Parse a line and dispatch it
75 protected int
76 parse_line(EditLine *el, const wchar_t *line)
78 const wchar_t **argv;
79 int argc;
80 TokenizerW *tok;
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;
90 /* el_parse():
91 * Command dispatcher
93 int
94 el_wparse(EditLine *el, int argc, const wchar_t *argv[])
96 const wchar_t *ptr;
97 int i;
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;
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];
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;
127 return -1;
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
135 protected int
136 parse__escape(const wchar_t **ptr)
138 const wchar_t *p;
139 wint_t c;
141 p = *ptr;
143 if (p[1] == 0)
144 return -1;
146 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 */
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;
191 if (c > 0x10FFFF) /* outside valid character range */
192 return -1;
193 break;
195 case '0':
196 case '1':
197 case '2':
198 case '3':
199 case '4':
200 case '5':
201 case '6':
202 case '7':
204 int cnt, ch;
206 for (cnt = 0, c = 0; cnt < 3; cnt++) {
207 ch = *p++;
208 if (ch < '0' || ch > '7') {
209 p--;
210 break;
212 c = (c << 3) | (ch - '0');
214 if ((c & 0xffffff00) != 0)
215 return -1;
216 --p;
217 break;
219 default:
220 c = *p;
221 break;
223 } else if (*p == '^') {
224 p++;
225 c = (*p == '?') ? '\177' : (*p & 0237);
226 } else
227 c = *p;
228 *ptr = ++p;
229 return c;
232 /* parse__string():
233 * Parse the escapes from in and put the raw string out
235 protected wchar_t *
236 parse__string(wchar_t *out, const wchar_t *in)
238 wchar_t *rv = out;
239 int n;
241 for (;;)
242 switch (*in) {
243 case '\0':
244 *out = '\0';
245 return rv;
247 case '\\':
248 case '^':
249 if ((n = parse__escape(&in)) == -1)
250 return NULL;
251 *out++ = (wchar_t)n;
252 break;
254 case 'M':
255 if (in[1] == '-' && in[2] != '\0') {
256 *out++ = '\033';
257 in += 2;
258 break;
260 /*FALLTHROUGH*/
262 default:
263 *out++ = *in++;
264 break;
269 /* parse_cmd():
270 * Return the command number for the command string given
271 * or -1 if one is not found
273 protected int
274 parse_cmd(EditLine *el, const wchar_t *cmd)
276 el_bindings_t *b;
277 int i;
279 for (b = el->el_map.help, i = 0; i < el->el_map.nfunc; i++)
280 if (wcscmp(b[i].name, cmd) == 0)
281 return b[i].func;
282 return -1;