1313981Spfg/*	$NetBSD: parse.c,v 1.35 2016/02/17 19:47:49 christos Exp $	*/
2276881Sbapt
31573Srgrimes/*-
41573Srgrimes * Copyright (c) 1992, 1993
51573Srgrimes *	The Regents of the University of California.  All rights reserved.
61573Srgrimes *
71573Srgrimes * This code is derived from software contributed to Berkeley by
81573Srgrimes * Christos Zoulas of Cornell University.
91573Srgrimes *
101573Srgrimes * Redistribution and use in source and binary forms, with or without
111573Srgrimes * modification, are permitted provided that the following conditions
121573Srgrimes * are met:
131573Srgrimes * 1. Redistributions of source code must retain the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer.
151573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161573Srgrimes *    notice, this list of conditions and the following disclaimer in the
171573Srgrimes *    documentation and/or other materials provided with the distribution.
18148834Sstefanf * 3. Neither the name of the University nor the names of its contributors
191573Srgrimes *    may be used to endorse or promote products derived from this software
201573Srgrimes *    without specific prior written permission.
211573Srgrimes *
221573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321573Srgrimes * SUCH DAMAGE.
331573Srgrimes */
341573Srgrimes
35276881Sbapt#include "config.h"
361573Srgrimes#if !defined(lint) && !defined(SCCSID)
37276881Sbapt#if 0
381573Srgrimesstatic char sccsid[] = "@(#)parse.c	8.1 (Berkeley) 6/4/93";
39276881Sbapt#else
40313981Spfg__RCSID("$NetBSD: parse.c,v 1.35 2016/02/17 19:47:49 christos Exp $");
41276881Sbapt#endif
421573Srgrimes#endif /* not lint && not SCCSID */
4384260Sobrien#include <sys/cdefs.h>
4484260Sobrien__FBSDID("$FreeBSD: stable/11/lib/libedit/parse.c 313981 2017-02-20 03:33:59Z pfg $");
451573Srgrimes
461573Srgrimes/*
471573Srgrimes * parse.c: parse an editline extended command
481573Srgrimes *
491573Srgrimes * commands are:
501573Srgrimes *
511573Srgrimes *	bind
521573Srgrimes *	echotc
5384260Sobrien *	edit
541573Srgrimes *	gettc
5526926Smsmith *	history
5626926Smsmith *	settc
5726926Smsmith *	setty
581573Srgrimes */
5984260Sobrien#include <stdlib.h>
60313981Spfg#include <string.h>
611573Srgrimes
62313981Spfg#include "el.h"
63313981Spfg#include "parse.h"
64313981Spfg
6584260Sobrienprivate const struct {
66276881Sbapt	const Char *name;
67276881Sbapt	int (*func)(EditLine *, int, const Char **);
681573Srgrimes} cmds[] = {
69313981Spfg	{ STR("bind"),		map_bind	},
70276881Sbapt	{ STR("echotc"),	terminal_echotc	},
71313981Spfg	{ STR("edit"),		el_editmode	},
72276881Sbapt	{ STR("history"),	hist_command	},
73276881Sbapt	{ STR("telltc"),	terminal_telltc	},
74276881Sbapt	{ STR("settc"),	        terminal_settc	},
75276881Sbapt	{ STR("setty"),	        tty_stty	},
76276881Sbapt	{ NULL,		        NULL		}
771573Srgrimes};
781573Srgrimes
791573Srgrimes
801573Srgrimes/* parse_line():
811573Srgrimes *	Parse a line and dispatch it
821573Srgrimes */
831573Srgrimesprotected int
84276881Sbaptparse_line(EditLine *el, const Char *line)
851573Srgrimes{
86276881Sbapt	const Char **argv;
8784260Sobrien	int argc;
88276881Sbapt	TYPE(Tokenizer) *tok;
891573Srgrimes
90276881Sbapt	tok = FUN(tok,init)(NULL);
91276881Sbapt	FUN(tok,str)(tok, line, &argc, &argv);
92276881Sbapt	argc = FUN(el,parse)(el, argc, argv);
93276881Sbapt	FUN(tok,end)(tok);
94276881Sbapt	return argc;
951573Srgrimes}
961573Srgrimes
9784260Sobrien
981573Srgrimes/* el_parse():
991573Srgrimes *	Command dispatcher
1001573Srgrimes */
1011573Srgrimespublic int
102276881SbaptFUN(el,parse)(EditLine *el, int argc, const Char *argv[])
1031573Srgrimes{
104276881Sbapt	const Char *ptr;
10584260Sobrien	int i;
1061573Srgrimes
10784260Sobrien	if (argc < 1)
108276881Sbapt		return -1;
109276881Sbapt	ptr = Strchr(argv[0], ':');
11084260Sobrien	if (ptr != NULL) {
111276881Sbapt		Char *tprog;
11284260Sobrien		size_t l;
1131573Srgrimes
11484260Sobrien		if (ptr == argv[0])
115276881Sbapt			return 0;
116276881Sbapt		l = (size_t)(ptr - argv[0] - 1);
117276881Sbapt		tprog = el_malloc((l + 1) * sizeof(*tprog));
11884260Sobrien		if (tprog == NULL)
119276881Sbapt			return 0;
120276881Sbapt		(void) Strncpy(tprog, argv[0], l);
12184260Sobrien		tprog[l] = '\0';
12284260Sobrien		ptr++;
123276881Sbapt		l = (size_t)el_match(el->el_prog, tprog);
12484260Sobrien		el_free(tprog);
12584260Sobrien		if (!l)
126276881Sbapt			return 0;
12784260Sobrien	} else
12884260Sobrien		ptr = argv[0];
1291573Srgrimes
13084260Sobrien	for (i = 0; cmds[i].name != NULL; i++)
131276881Sbapt		if (Strcmp(cmds[i].name, ptr) == 0) {
13284260Sobrien			i = (*cmds[i].func) (el, argc, argv);
133276881Sbapt			return -i;
13484260Sobrien		}
135276881Sbapt	return -1;
1361573Srgrimes}
1371573Srgrimes
1381573Srgrimes
1391573Srgrimes/* parse__escape():
140276881Sbapt *	Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return
1411573Srgrimes *	the appropriate character or -1 if the escape is not valid
1421573Srgrimes */
1431573Srgrimesprotected int
144276881Sbaptparse__escape(const Char **ptr)
1451573Srgrimes{
146276881Sbapt	const Char *p;
147313981Spfg	wint_t c;
1481573Srgrimes
14984260Sobrien	p = *ptr;
1501573Srgrimes
15184260Sobrien	if (p[1] == 0)
152276881Sbapt		return -1;
1531573Srgrimes
15484260Sobrien	if (*p == '\\') {
15584260Sobrien		p++;
15684260Sobrien		switch (*p) {
15784260Sobrien		case 'a':
15884260Sobrien			c = '\007';	/* Bell */
15984260Sobrien			break;
16084260Sobrien		case 'b':
16184260Sobrien			c = '\010';	/* Backspace */
16284260Sobrien			break;
16384260Sobrien		case 't':
16484260Sobrien			c = '\011';	/* Horizontal Tab */
16584260Sobrien			break;
16684260Sobrien		case 'n':
16784260Sobrien			c = '\012';	/* New Line */
16884260Sobrien			break;
16984260Sobrien		case 'v':
17084260Sobrien			c = '\013';	/* Vertical Tab */
17184260Sobrien			break;
17284260Sobrien		case 'f':
17384260Sobrien			c = '\014';	/* Form Feed */
17484260Sobrien			break;
17584260Sobrien		case 'r':
17684260Sobrien			c = '\015';	/* Carriage Return */
17784260Sobrien			break;
17884260Sobrien		case 'e':
17984260Sobrien			c = '\033';	/* Escape */
18084260Sobrien			break;
181276881Sbapt                case 'U':               /* Unicode \U+xxxx or \U+xxxxx format */
182276881Sbapt                {
183276881Sbapt                        int i;
184276881Sbapt                        const Char hex[] = STR("0123456789ABCDEF");
185276881Sbapt                        const Char *h;
186276881Sbapt                        ++p;
187276881Sbapt                        if (*p++ != '+')
188276881Sbapt                                return -1;
189276881Sbapt			c = 0;
190276881Sbapt                        for (i = 0; i < 5; ++i) {
191276881Sbapt                                h = Strchr(hex, *p++);
192276881Sbapt                                if (!h && i < 4)
193276881Sbapt                                        return -1;
194276881Sbapt                                else if (h)
195276881Sbapt                                        c = (c << 4) | ((int)(h - hex));
196276881Sbapt                                else
197276881Sbapt                                        --p;
198276881Sbapt                        }
199276881Sbapt                        if (c > 0x10FFFF) /* outside valid character range */
200276881Sbapt                                return -1;
201276881Sbapt                        break;
202276881Sbapt                }
20384260Sobrien		case '0':
20484260Sobrien		case '1':
20584260Sobrien		case '2':
20684260Sobrien		case '3':
20784260Sobrien		case '4':
20884260Sobrien		case '5':
20984260Sobrien		case '6':
21084260Sobrien		case '7':
21184260Sobrien		{
21284260Sobrien			int cnt, ch;
2131573Srgrimes
21484260Sobrien			for (cnt = 0, c = 0; cnt < 3; cnt++) {
21584260Sobrien				ch = *p++;
21684260Sobrien				if (ch < '0' || ch > '7') {
21784260Sobrien					p--;
21884260Sobrien					break;
21984260Sobrien				}
22084260Sobrien				c = (c << 3) | (ch - '0');
22184260Sobrien			}
222276881Sbapt			if ((c & (wint_t)0xffffff00) != (wint_t)0)
223276881Sbapt				return -1;
22484260Sobrien			--p;
2251573Srgrimes			break;
2261573Srgrimes		}
22784260Sobrien		default:
22884260Sobrien			c = *p;
22984260Sobrien			break;
23084260Sobrien		}
231148834Sstefanf	} else if (*p == '^') {
23284260Sobrien		p++;
23384260Sobrien		c = (*p == '?') ? '\177' : (*p & 0237);
23484260Sobrien	} else
23584260Sobrien		c = *p;
23684260Sobrien	*ptr = ++p;
237276881Sbapt	return c;
2381573Srgrimes}
239148834Sstefanf
2401573Srgrimes/* parse__string():
2411573Srgrimes *	Parse the escapes from in and put the raw string out
2421573Srgrimes */
243276881Sbaptprotected Char *
244276881Sbaptparse__string(Char *out, const Char *in)
2451573Srgrimes{
246276881Sbapt	Char *rv = out;
24784260Sobrien	int n;
2481573Srgrimes
24984260Sobrien	for (;;)
25084260Sobrien		switch (*in) {
25184260Sobrien		case '\0':
25284260Sobrien			*out = '\0';
253276881Sbapt			return rv;
2541573Srgrimes
25584260Sobrien		case '\\':
25684260Sobrien		case '^':
25784260Sobrien			if ((n = parse__escape(&in)) == -1)
258276881Sbapt				return NULL;
259313981Spfg			*out++ = (Char)n;
26084260Sobrien			break;
26184260Sobrien
262148834Sstefanf		case 'M':
263148834Sstefanf			if (in[1] == '-' && in[2] != '\0') {
264148834Sstefanf				*out++ = '\033';
265148834Sstefanf				in += 2;
266148834Sstefanf				break;
267148834Sstefanf			}
268148834Sstefanf			/*FALLTHROUGH*/
269148834Sstefanf
27084260Sobrien		default:
27184260Sobrien			*out++ = *in++;
27284260Sobrien			break;
27384260Sobrien		}
2741573Srgrimes}
2751573Srgrimes
27684260Sobrien
2771573Srgrimes/* parse_cmd():
2781573Srgrimes *	Return the command number for the command string given
2791573Srgrimes *	or -1 if one is not found
2801573Srgrimes */
2811573Srgrimesprotected int
282276881Sbaptparse_cmd(EditLine *el, const Char *cmd)
2831573Srgrimes{
284276881Sbapt	el_bindings_t *b = el->el_map.help;
285276881Sbapt	size_t i;
2861573Srgrimes
287276881Sbapt	for (i = 0; i < el->el_map.nfunc; i++)
288276881Sbapt		if (Strcmp(b[i].name, cmd) == 0)
289276881Sbapt			return b[i].func;
290276881Sbapt	return -1;
2911573Srgrimes}
292