1*113f06a3Schristos /* $NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 christos Exp $ */
22543e3e6Slukem
36dc2f1dbScgd /*-
46dc2f1dbScgd * Copyright (c) 1992, 1993
56dc2f1dbScgd * The Regents of the University of California. All rights reserved.
66dc2f1dbScgd *
76dc2f1dbScgd * This code is derived from software contributed to Berkeley by
86dc2f1dbScgd * Christos Zoulas of Cornell University.
96dc2f1dbScgd *
106dc2f1dbScgd * Redistribution and use in source and binary forms, with or without
116dc2f1dbScgd * modification, are permitted provided that the following conditions
126dc2f1dbScgd * are met:
136dc2f1dbScgd * 1. Redistributions of source code must retain the above copyright
146dc2f1dbScgd * notice, this list of conditions and the following disclaimer.
156dc2f1dbScgd * 2. Redistributions in binary form must reproduce the above copyright
166dc2f1dbScgd * notice, this list of conditions and the following disclaimer in the
176dc2f1dbScgd * documentation and/or other materials provided with the distribution.
18eb7c1594Sagc * 3. Neither the name of the University nor the names of its contributors
196dc2f1dbScgd * may be used to endorse or promote products derived from this software
206dc2f1dbScgd * without specific prior written permission.
216dc2f1dbScgd *
226dc2f1dbScgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
236dc2f1dbScgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
246dc2f1dbScgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
256dc2f1dbScgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
266dc2f1dbScgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
276dc2f1dbScgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
286dc2f1dbScgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
296dc2f1dbScgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
306dc2f1dbScgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
316dc2f1dbScgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326dc2f1dbScgd * SUCH DAMAGE.
336dc2f1dbScgd */
346dc2f1dbScgd
350e0ac6b7Schristos #include "config.h"
366dc2f1dbScgd #if !defined(lint) && !defined(SCCSID)
372543e3e6Slukem #if 0
386dc2f1dbScgd static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93";
392543e3e6Slukem #else
40*113f06a3Schristos __RCSID("$NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 christos Exp $");
412543e3e6Slukem #endif
426dc2f1dbScgd #endif /* not lint && not SCCSID */
436dc2f1dbScgd
446dc2f1dbScgd /*
456dc2f1dbScgd * parse.c: parse an editline extended command
466dc2f1dbScgd *
476dc2f1dbScgd * commands are:
486dc2f1dbScgd *
496dc2f1dbScgd * bind
506dc2f1dbScgd * echotc
51f87d2504Slukem * edit
526dc2f1dbScgd * gettc
532543e3e6Slukem * history
542543e3e6Slukem * settc
552543e3e6Slukem * setty
566dc2f1dbScgd */
57aefc1e44Schristos #include <stdlib.h>
58e84df91eSchristos #include <string.h>
5940850369Schristos
60747f6811Schristos #include "el.h"
61747f6811Schristos #include "parse.h"
62747f6811Schristos
63469d44f8Schristos static const struct {
640594af80Schristos const wchar_t *name;
650594af80Schristos int (*func)(EditLine *, int, const wchar_t **);
666dc2f1dbScgd } cmds[] = {
670aefc7f9Schristos { L"bind", map_bind },
680aefc7f9Schristos { L"echotc", terminal_echotc },
690aefc7f9Schristos { L"edit", el_editmode },
700aefc7f9Schristos { L"history", hist_command },
710aefc7f9Schristos { L"telltc", terminal_telltc },
720aefc7f9Schristos { L"settc", terminal_settc },
730aefc7f9Schristos { L"setty", tty_stty },
746dc2f1dbScgd { NULL, NULL }
756dc2f1dbScgd };
766dc2f1dbScgd
776dc2f1dbScgd
786dc2f1dbScgd /* parse_line():
796dc2f1dbScgd * Parse a line and dispatch it
806dc2f1dbScgd */
81a2d6b270Schristos libedit_private int
parse_line(EditLine * el,const wchar_t * line)820594af80Schristos parse_line(EditLine *el, const wchar_t *line)
836dc2f1dbScgd {
840594af80Schristos const wchar_t **argv;
856dc2f1dbScgd int argc;
860aefc7f9Schristos TokenizerW *tok;
876dc2f1dbScgd
880aefc7f9Schristos tok = tok_winit(NULL);
890aefc7f9Schristos tok_wstr(tok, line, &argc, &argv);
900aefc7f9Schristos argc = el_wparse(el, argc, argv);
910aefc7f9Schristos tok_wend(tok);
92b71bed95Schristos return argc;
936dc2f1dbScgd }
946dc2f1dbScgd
95d30d584aSlukem
966dc2f1dbScgd /* el_parse():
976dc2f1dbScgd * Command dispatcher
986dc2f1dbScgd */
99469d44f8Schristos int
el_wparse(EditLine * el,int argc,const wchar_t * argv[])1000594af80Schristos el_wparse(EditLine *el, int argc, const wchar_t *argv[])
1016dc2f1dbScgd {
1020594af80Schristos const wchar_t *ptr;
1036dc2f1dbScgd int i;
1046dc2f1dbScgd
105258ebfd2Slukem if (argc < 1)
106b71bed95Schristos return -1;
1070aefc7f9Schristos ptr = wcschr(argv[0], L':');
108b59d3eafSlukem if (ptr != NULL) {
1090594af80Schristos wchar_t *tprog;
110a6d4afbaSchristos size_t l;
11163177b84Slukem
1120d4dea92Schristos if (ptr == argv[0])
113b71bed95Schristos return 0;
114f04c2e3eSchristos l = (size_t)(ptr - argv[0]);
115*113f06a3Schristos tprog = el_calloc(l + 1, sizeof(*tprog));
11663177b84Slukem if (tprog == NULL)
117b71bed95Schristos return 0;
1180aefc7f9Schristos (void) wcsncpy(tprog, argv[0], l);
11963177b84Slukem tprog[l] = '\0';
12063177b84Slukem ptr++;
1213d802cf5Schristos l = (size_t)el_match(el->el_prog, tprog);
1220d4dea92Schristos el_free(tprog);
12363177b84Slukem if (!l)
124b71bed95Schristos return 0;
125d30d584aSlukem } else
1266dc2f1dbScgd ptr = argv[0];
1276dc2f1dbScgd
1286dc2f1dbScgd for (i = 0; cmds[i].name != NULL; i++)
1290aefc7f9Schristos if (wcscmp(cmds[i].name, ptr) == 0) {
1306dc2f1dbScgd i = (*cmds[i].func) (el, argc, argv);
131b71bed95Schristos return -i;
1326dc2f1dbScgd }
133b71bed95Schristos return -1;
1346dc2f1dbScgd }
1356dc2f1dbScgd
1366dc2f1dbScgd
1376dc2f1dbScgd /* parse__escape():
13834e53048Schristos * Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return
1396dc2f1dbScgd * the appropriate character or -1 if the escape is not valid
1406dc2f1dbScgd */
141a2d6b270Schristos libedit_private int
parse__escape(const wchar_t ** ptr)1420594af80Schristos parse__escape(const wchar_t **ptr)
1436dc2f1dbScgd {
1440594af80Schristos const wchar_t *p;
145f54e4f97Schristos wint_t c;
1466dc2f1dbScgd
1476dc2f1dbScgd p = *ptr;
1486dc2f1dbScgd
1496dc2f1dbScgd if (p[1] == 0)
150b71bed95Schristos return -1;
1516dc2f1dbScgd
1526dc2f1dbScgd if (*p == '\\') {
1536dc2f1dbScgd p++;
1546dc2f1dbScgd switch (*p) {
1556dc2f1dbScgd case 'a':
1566dc2f1dbScgd c = '\007'; /* Bell */
1576dc2f1dbScgd break;
1586dc2f1dbScgd case 'b':
1596dc2f1dbScgd c = '\010'; /* Backspace */
1606dc2f1dbScgd break;
1616dc2f1dbScgd case 't':
1626dc2f1dbScgd c = '\011'; /* Horizontal Tab */
1636dc2f1dbScgd break;
1646dc2f1dbScgd case 'n':
1656dc2f1dbScgd c = '\012'; /* New Line */
1666dc2f1dbScgd break;
1676dc2f1dbScgd case 'v':
1686dc2f1dbScgd c = '\013'; /* Vertical Tab */
1696dc2f1dbScgd break;
1706dc2f1dbScgd case 'f':
1716dc2f1dbScgd c = '\014'; /* Form Feed */
1726dc2f1dbScgd break;
1736dc2f1dbScgd case 'r':
1746dc2f1dbScgd c = '\015'; /* Carriage Return */
1756dc2f1dbScgd break;
1766dc2f1dbScgd case 'e':
1776dc2f1dbScgd c = '\033'; /* Escape */
1786dc2f1dbScgd break;
17934e53048Schristos case 'U': /* Unicode \U+xxxx or \U+xxxxx format */
18034e53048Schristos {
18134e53048Schristos int i;
1820594af80Schristos const wchar_t hex[] = L"0123456789ABCDEF";
1830594af80Schristos const wchar_t *h;
18434e53048Schristos ++p;
18534e53048Schristos if (*p++ != '+')
186b71bed95Schristos return -1;
18734e53048Schristos c = 0;
18834e53048Schristos for (i = 0; i < 5; ++i) {
1890aefc7f9Schristos h = wcschr(hex, *p++);
19034e53048Schristos if (!h && i < 4)
191b71bed95Schristos return -1;
19234e53048Schristos else if (h)
19334e53048Schristos c = (c << 4) | ((int)(h - hex));
19434e53048Schristos else
19534e53048Schristos --p;
19634e53048Schristos }
19734e53048Schristos if (c > 0x10FFFF) /* outside valid character range */
19834e53048Schristos return -1;
19934e53048Schristos break;
20034e53048Schristos }
2016dc2f1dbScgd case '0':
2026dc2f1dbScgd case '1':
2036dc2f1dbScgd case '2':
2046dc2f1dbScgd case '3':
2056dc2f1dbScgd case '4':
2066dc2f1dbScgd case '5':
2076dc2f1dbScgd case '6':
2086dc2f1dbScgd case '7':
2096dc2f1dbScgd {
2106dc2f1dbScgd int cnt, ch;
2116dc2f1dbScgd
2126dc2f1dbScgd for (cnt = 0, c = 0; cnt < 3; cnt++) {
2136dc2f1dbScgd ch = *p++;
2146dc2f1dbScgd if (ch < '0' || ch > '7') {
2156dc2f1dbScgd p--;
2166dc2f1dbScgd break;
2176dc2f1dbScgd }
2186dc2f1dbScgd c = (c << 3) | (ch - '0');
2196dc2f1dbScgd }
2203d802cf5Schristos if ((c & (wint_t)0xffffff00) != (wint_t)0)
221b71bed95Schristos return -1;
2226dc2f1dbScgd --p;
2236dc2f1dbScgd break;
224d30d584aSlukem }
2256dc2f1dbScgd default:
2266dc2f1dbScgd c = *p;
2276dc2f1dbScgd break;
2286dc2f1dbScgd }
229378865a4Schristos } else if (*p == '^') {
2306dc2f1dbScgd p++;
2316dc2f1dbScgd c = (*p == '?') ? '\177' : (*p & 0237);
232d30d584aSlukem } else
2336dc2f1dbScgd c = *p;
2346dc2f1dbScgd *ptr = ++p;
235b71bed95Schristos return c;
2366dc2f1dbScgd }
237d67d488eSchristos
2386dc2f1dbScgd /* parse__string():
2396dc2f1dbScgd * Parse the escapes from in and put the raw string out
2406dc2f1dbScgd */
241a2d6b270Schristos libedit_private wchar_t *
parse__string(wchar_t * out,const wchar_t * in)2420594af80Schristos parse__string(wchar_t *out, const wchar_t *in)
2436dc2f1dbScgd {
2440594af80Schristos wchar_t *rv = out;
2456dc2f1dbScgd int n;
246d30d584aSlukem
2476dc2f1dbScgd for (;;)
2486dc2f1dbScgd switch (*in) {
2496dc2f1dbScgd case '\0':
2506dc2f1dbScgd *out = '\0';
251b71bed95Schristos return rv;
2526dc2f1dbScgd
2536dc2f1dbScgd case '\\':
2546dc2f1dbScgd case '^':
2556dc2f1dbScgd if ((n = parse__escape(&in)) == -1)
256b71bed95Schristos return NULL;
2570594af80Schristos *out++ = (wchar_t)n;
2586dc2f1dbScgd break;
2596dc2f1dbScgd
260d67d488eSchristos case 'M':
261d67d488eSchristos if (in[1] == '-' && in[2] != '\0') {
262d67d488eSchristos *out++ = '\033';
263d67d488eSchristos in += 2;
264d67d488eSchristos break;
265d67d488eSchristos }
266d67d488eSchristos /*FALLTHROUGH*/
267d67d488eSchristos
2686dc2f1dbScgd default:
2696dc2f1dbScgd *out++ = *in++;
2706dc2f1dbScgd break;
2716dc2f1dbScgd }
2726dc2f1dbScgd }
2736dc2f1dbScgd
274d30d584aSlukem
2756dc2f1dbScgd /* parse_cmd():
2766dc2f1dbScgd * Return the command number for the command string given
2776dc2f1dbScgd * or -1 if one is not found
2786dc2f1dbScgd */
279a2d6b270Schristos libedit_private int
parse_cmd(EditLine * el,const wchar_t * cmd)2800594af80Schristos parse_cmd(EditLine *el, const wchar_t *cmd)
2816dc2f1dbScgd {
28280e781abSchristos el_bindings_t *b = el->el_map.help;
28380e781abSchristos size_t i;
2846dc2f1dbScgd
28580e781abSchristos for (i = 0; i < el->el_map.nfunc; i++)
2860aefc7f9Schristos if (wcscmp(b[i].name, cmd) == 0)
28780e781abSchristos return b[i].func;
288b71bed95Schristos return -1;
2896dc2f1dbScgd }
290