xref: /minix/lib/libedit/parse.c (revision 0a6a1f1d)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: parse.c,v 1.27 2014/07/06 18:15:34 christos Exp $	*/
23e1db26aSLionel Sambuc 
33e1db26aSLionel Sambuc /*-
43e1db26aSLionel Sambuc  * Copyright (c) 1992, 1993
53e1db26aSLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
63e1db26aSLionel Sambuc  *
73e1db26aSLionel Sambuc  * This code is derived from software contributed to Berkeley by
83e1db26aSLionel Sambuc  * Christos Zoulas of Cornell University.
93e1db26aSLionel Sambuc  *
103e1db26aSLionel Sambuc  * Redistribution and use in source and binary forms, with or without
113e1db26aSLionel Sambuc  * modification, are permitted provided that the following conditions
123e1db26aSLionel Sambuc  * are met:
133e1db26aSLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
143e1db26aSLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
153e1db26aSLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
163e1db26aSLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
173e1db26aSLionel Sambuc  *    documentation and/or other materials provided with the distribution.
183e1db26aSLionel Sambuc  * 3. Neither the name of the University nor the names of its contributors
193e1db26aSLionel Sambuc  *    may be used to endorse or promote products derived from this software
203e1db26aSLionel Sambuc  *    without specific prior written permission.
213e1db26aSLionel Sambuc  *
223e1db26aSLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233e1db26aSLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243e1db26aSLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253e1db26aSLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263e1db26aSLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273e1db26aSLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283e1db26aSLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293e1db26aSLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303e1db26aSLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313e1db26aSLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323e1db26aSLionel Sambuc  * SUCH DAMAGE.
333e1db26aSLionel Sambuc  */
343e1db26aSLionel Sambuc 
353e1db26aSLionel Sambuc #include "config.h"
363e1db26aSLionel Sambuc #if !defined(lint) && !defined(SCCSID)
373e1db26aSLionel Sambuc #if 0
383e1db26aSLionel Sambuc static char sccsid[] = "@(#)parse.c	8.1 (Berkeley) 6/4/93";
393e1db26aSLionel Sambuc #else
40*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: parse.c,v 1.27 2014/07/06 18:15:34 christos Exp $");
413e1db26aSLionel Sambuc #endif
423e1db26aSLionel Sambuc #endif /* not lint && not SCCSID */
433e1db26aSLionel Sambuc 
443e1db26aSLionel Sambuc /*
453e1db26aSLionel Sambuc  * parse.c: parse an editline extended command
463e1db26aSLionel Sambuc  *
473e1db26aSLionel Sambuc  * commands are:
483e1db26aSLionel Sambuc  *
493e1db26aSLionel Sambuc  *	bind
503e1db26aSLionel Sambuc  *	echotc
513e1db26aSLionel Sambuc  *	edit
523e1db26aSLionel Sambuc  *	gettc
533e1db26aSLionel Sambuc  *	history
543e1db26aSLionel Sambuc  *	settc
553e1db26aSLionel Sambuc  *	setty
563e1db26aSLionel Sambuc  */
573e1db26aSLionel Sambuc #include "el.h"
583e1db26aSLionel Sambuc #include <stdlib.h>
593e1db26aSLionel Sambuc 
603e1db26aSLionel Sambuc private const struct {
613e1db26aSLionel Sambuc 	const Char *name;
623e1db26aSLionel Sambuc 	int (*func)(EditLine *, int, const Char **);
633e1db26aSLionel Sambuc } cmds[] = {
643e1db26aSLionel Sambuc 	{ STR("bind"),  	map_bind	},
653e1db26aSLionel Sambuc 	{ STR("echotc"),	terminal_echotc	},
663e1db26aSLionel Sambuc 	{ STR("edit"),  	el_editmode	},
673e1db26aSLionel Sambuc 	{ STR("history"),	hist_command	},
683e1db26aSLionel Sambuc 	{ STR("telltc"),	terminal_telltc	},
693e1db26aSLionel Sambuc 	{ STR("settc"),	        terminal_settc	},
703e1db26aSLionel Sambuc 	{ STR("setty"),	        tty_stty	},
713e1db26aSLionel Sambuc 	{ NULL,		        NULL		}
723e1db26aSLionel Sambuc };
733e1db26aSLionel Sambuc 
743e1db26aSLionel Sambuc 
753e1db26aSLionel Sambuc /* parse_line():
763e1db26aSLionel Sambuc  *	Parse a line and dispatch it
773e1db26aSLionel Sambuc  */
783e1db26aSLionel Sambuc protected int
parse_line(EditLine * el,const Char * line)793e1db26aSLionel Sambuc parse_line(EditLine *el, const Char *line)
803e1db26aSLionel Sambuc {
813e1db26aSLionel Sambuc 	const Char **argv;
823e1db26aSLionel Sambuc 	int argc;
833e1db26aSLionel Sambuc 	TYPE(Tokenizer) *tok;
843e1db26aSLionel Sambuc 
853e1db26aSLionel Sambuc 	tok = FUN(tok,init)(NULL);
863e1db26aSLionel Sambuc 	FUN(tok,str)(tok, line, &argc, &argv);
873e1db26aSLionel Sambuc 	argc = FUN(el,parse)(el, argc, argv);
883e1db26aSLionel Sambuc 	FUN(tok,end)(tok);
893e1db26aSLionel Sambuc 	return argc;
903e1db26aSLionel Sambuc }
913e1db26aSLionel Sambuc 
923e1db26aSLionel Sambuc 
933e1db26aSLionel Sambuc /* el_parse():
943e1db26aSLionel Sambuc  *	Command dispatcher
953e1db26aSLionel Sambuc  */
963e1db26aSLionel Sambuc public int
FUN(el,parse)973e1db26aSLionel Sambuc FUN(el,parse)(EditLine *el, int argc, const Char *argv[])
983e1db26aSLionel Sambuc {
993e1db26aSLionel Sambuc 	const Char *ptr;
1003e1db26aSLionel Sambuc 	int i;
1013e1db26aSLionel Sambuc 
1023e1db26aSLionel Sambuc 	if (argc < 1)
1033e1db26aSLionel Sambuc 		return -1;
1043e1db26aSLionel Sambuc 	ptr = Strchr(argv[0], ':');
1053e1db26aSLionel Sambuc 	if (ptr != NULL) {
1063e1db26aSLionel Sambuc 		Char *tprog;
1073e1db26aSLionel Sambuc 		size_t l;
1083e1db26aSLionel Sambuc 
1093e1db26aSLionel Sambuc 		if (ptr == argv[0])
1103e1db26aSLionel Sambuc 			return 0;
1113e1db26aSLionel Sambuc 		l = (size_t)(ptr - argv[0] - 1);
1123e1db26aSLionel Sambuc 		tprog = el_malloc((l + 1) * sizeof(*tprog));
1133e1db26aSLionel Sambuc 		if (tprog == NULL)
1143e1db26aSLionel Sambuc 			return 0;
1153e1db26aSLionel Sambuc 		(void) Strncpy(tprog, argv[0], l);
1163e1db26aSLionel Sambuc 		tprog[l] = '\0';
1173e1db26aSLionel Sambuc 		ptr++;
1183e1db26aSLionel Sambuc 		l = (size_t)el_match(el->el_prog, tprog);
1193e1db26aSLionel Sambuc 		el_free(tprog);
1203e1db26aSLionel Sambuc 		if (!l)
1213e1db26aSLionel Sambuc 			return 0;
1223e1db26aSLionel Sambuc 	} else
1233e1db26aSLionel Sambuc 		ptr = argv[0];
1243e1db26aSLionel Sambuc 
1253e1db26aSLionel Sambuc 	for (i = 0; cmds[i].name != NULL; i++)
1263e1db26aSLionel Sambuc 		if (Strcmp(cmds[i].name, ptr) == 0) {
1273e1db26aSLionel Sambuc 			i = (*cmds[i].func) (el, argc, argv);
1283e1db26aSLionel Sambuc 			return -i;
1293e1db26aSLionel Sambuc 		}
1303e1db26aSLionel Sambuc 	return -1;
1313e1db26aSLionel Sambuc }
1323e1db26aSLionel Sambuc 
1333e1db26aSLionel Sambuc 
1343e1db26aSLionel Sambuc /* parse__escape():
1353e1db26aSLionel Sambuc  *	Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return
1363e1db26aSLionel Sambuc  *	the appropriate character or -1 if the escape is not valid
1373e1db26aSLionel Sambuc  */
1383e1db26aSLionel Sambuc protected int
parse__escape(const Char ** ptr)1393e1db26aSLionel Sambuc parse__escape(const Char **ptr)
1403e1db26aSLionel Sambuc {
1413e1db26aSLionel Sambuc 	const Char *p;
1423e1db26aSLionel Sambuc 	Int c;
1433e1db26aSLionel Sambuc 
1443e1db26aSLionel Sambuc 	p = *ptr;
1453e1db26aSLionel Sambuc 
1463e1db26aSLionel Sambuc 	if (p[1] == 0)
1473e1db26aSLionel Sambuc 		return -1;
1483e1db26aSLionel Sambuc 
1493e1db26aSLionel Sambuc 	if (*p == '\\') {
1503e1db26aSLionel Sambuc 		p++;
1513e1db26aSLionel Sambuc 		switch (*p) {
1523e1db26aSLionel Sambuc 		case 'a':
1533e1db26aSLionel Sambuc 			c = '\007';	/* Bell */
1543e1db26aSLionel Sambuc 			break;
1553e1db26aSLionel Sambuc 		case 'b':
1563e1db26aSLionel Sambuc 			c = '\010';	/* Backspace */
1573e1db26aSLionel Sambuc 			break;
1583e1db26aSLionel Sambuc 		case 't':
1593e1db26aSLionel Sambuc 			c = '\011';	/* Horizontal Tab */
1603e1db26aSLionel Sambuc 			break;
1613e1db26aSLionel Sambuc 		case 'n':
1623e1db26aSLionel Sambuc 			c = '\012';	/* New Line */
1633e1db26aSLionel Sambuc 			break;
1643e1db26aSLionel Sambuc 		case 'v':
1653e1db26aSLionel Sambuc 			c = '\013';	/* Vertical Tab */
1663e1db26aSLionel Sambuc 			break;
1673e1db26aSLionel Sambuc 		case 'f':
1683e1db26aSLionel Sambuc 			c = '\014';	/* Form Feed */
1693e1db26aSLionel Sambuc 			break;
1703e1db26aSLionel Sambuc 		case 'r':
1713e1db26aSLionel Sambuc 			c = '\015';	/* Carriage Return */
1723e1db26aSLionel Sambuc 			break;
1733e1db26aSLionel Sambuc 		case 'e':
1743e1db26aSLionel Sambuc 			c = '\033';	/* Escape */
1753e1db26aSLionel Sambuc 			break;
1763e1db26aSLionel Sambuc                 case 'U':               /* Unicode \U+xxxx or \U+xxxxx format */
1773e1db26aSLionel Sambuc                 {
1783e1db26aSLionel Sambuc                         int i;
1793e1db26aSLionel Sambuc                         const Char hex[] = STR("0123456789ABCDEF");
1803e1db26aSLionel Sambuc                         const Char *h;
1813e1db26aSLionel Sambuc                         ++p;
1823e1db26aSLionel Sambuc                         if (*p++ != '+')
1833e1db26aSLionel Sambuc                                 return -1;
1843e1db26aSLionel Sambuc 			c = 0;
1853e1db26aSLionel Sambuc                         for (i = 0; i < 5; ++i) {
1863e1db26aSLionel Sambuc                                 h = Strchr(hex, *p++);
1873e1db26aSLionel Sambuc                                 if (!h && i < 4)
1883e1db26aSLionel Sambuc                                         return -1;
1893e1db26aSLionel Sambuc                                 else if (h)
1903e1db26aSLionel Sambuc                                         c = (c << 4) | ((int)(h - hex));
1913e1db26aSLionel Sambuc                                 else
1923e1db26aSLionel Sambuc                                         --p;
1933e1db26aSLionel Sambuc                         }
1943e1db26aSLionel Sambuc                         if (c > 0x10FFFF) /* outside valid character range */
1953e1db26aSLionel Sambuc                                 return -1;
1963e1db26aSLionel Sambuc                         break;
1973e1db26aSLionel Sambuc                 }
1983e1db26aSLionel Sambuc 		case '0':
1993e1db26aSLionel Sambuc 		case '1':
2003e1db26aSLionel Sambuc 		case '2':
2013e1db26aSLionel Sambuc 		case '3':
2023e1db26aSLionel Sambuc 		case '4':
2033e1db26aSLionel Sambuc 		case '5':
2043e1db26aSLionel Sambuc 		case '6':
2053e1db26aSLionel Sambuc 		case '7':
2063e1db26aSLionel Sambuc 		{
2073e1db26aSLionel Sambuc 			int cnt, ch;
2083e1db26aSLionel Sambuc 
2093e1db26aSLionel Sambuc 			for (cnt = 0, c = 0; cnt < 3; cnt++) {
2103e1db26aSLionel Sambuc 				ch = *p++;
2113e1db26aSLionel Sambuc 				if (ch < '0' || ch > '7') {
2123e1db26aSLionel Sambuc 					p--;
2133e1db26aSLionel Sambuc 					break;
2143e1db26aSLionel Sambuc 				}
2153e1db26aSLionel Sambuc 				c = (c << 3) | (ch - '0');
2163e1db26aSLionel Sambuc 			}
2173e1db26aSLionel Sambuc 			if ((c & (wint_t)0xffffff00) != (wint_t)0)
2183e1db26aSLionel Sambuc 				return -1;
2193e1db26aSLionel Sambuc 			--p;
2203e1db26aSLionel Sambuc 			break;
2213e1db26aSLionel Sambuc 		}
2223e1db26aSLionel Sambuc 		default:
2233e1db26aSLionel Sambuc 			c = *p;
2243e1db26aSLionel Sambuc 			break;
2253e1db26aSLionel Sambuc 		}
2263e1db26aSLionel Sambuc 	} else if (*p == '^') {
2273e1db26aSLionel Sambuc 		p++;
2283e1db26aSLionel Sambuc 		c = (*p == '?') ? '\177' : (*p & 0237);
2293e1db26aSLionel Sambuc 	} else
2303e1db26aSLionel Sambuc 		c = *p;
2313e1db26aSLionel Sambuc 	*ptr = ++p;
2323e1db26aSLionel Sambuc 	return c;
2333e1db26aSLionel Sambuc }
2343e1db26aSLionel Sambuc 
2353e1db26aSLionel Sambuc /* parse__string():
2363e1db26aSLionel Sambuc  *	Parse the escapes from in and put the raw string out
2373e1db26aSLionel Sambuc  */
2383e1db26aSLionel Sambuc protected Char *
parse__string(Char * out,const Char * in)2393e1db26aSLionel Sambuc parse__string(Char *out, const Char *in)
2403e1db26aSLionel Sambuc {
2413e1db26aSLionel Sambuc 	Char *rv = out;
2423e1db26aSLionel Sambuc 	int n;
2433e1db26aSLionel Sambuc 
2443e1db26aSLionel Sambuc 	for (;;)
2453e1db26aSLionel Sambuc 		switch (*in) {
2463e1db26aSLionel Sambuc 		case '\0':
2473e1db26aSLionel Sambuc 			*out = '\0';
2483e1db26aSLionel Sambuc 			return rv;
2493e1db26aSLionel Sambuc 
2503e1db26aSLionel Sambuc 		case '\\':
2513e1db26aSLionel Sambuc 		case '^':
2523e1db26aSLionel Sambuc 			if ((n = parse__escape(&in)) == -1)
2533e1db26aSLionel Sambuc 				return NULL;
2543e1db26aSLionel Sambuc 			*out++ = n;
2553e1db26aSLionel Sambuc 			break;
2563e1db26aSLionel Sambuc 
2573e1db26aSLionel Sambuc 		case 'M':
2583e1db26aSLionel Sambuc 			if (in[1] == '-' && in[2] != '\0') {
2593e1db26aSLionel Sambuc 				*out++ = '\033';
2603e1db26aSLionel Sambuc 				in += 2;
2613e1db26aSLionel Sambuc 				break;
2623e1db26aSLionel Sambuc 			}
2633e1db26aSLionel Sambuc 			/*FALLTHROUGH*/
2643e1db26aSLionel Sambuc 
2653e1db26aSLionel Sambuc 		default:
2663e1db26aSLionel Sambuc 			*out++ = *in++;
2673e1db26aSLionel Sambuc 			break;
2683e1db26aSLionel Sambuc 		}
2693e1db26aSLionel Sambuc }
2703e1db26aSLionel Sambuc 
2713e1db26aSLionel Sambuc 
2723e1db26aSLionel Sambuc /* parse_cmd():
2733e1db26aSLionel Sambuc  *	Return the command number for the command string given
2743e1db26aSLionel Sambuc  *	or -1 if one is not found
2753e1db26aSLionel Sambuc  */
2763e1db26aSLionel Sambuc protected int
parse_cmd(EditLine * el,const Char * cmd)2773e1db26aSLionel Sambuc parse_cmd(EditLine *el, const Char *cmd)
2783e1db26aSLionel Sambuc {
279*0a6a1f1dSLionel Sambuc 	el_bindings_t *b = el->el_map.help;
280*0a6a1f1dSLionel Sambuc 	size_t i;
2813e1db26aSLionel Sambuc 
282*0a6a1f1dSLionel Sambuc 	for (i = 0; i < el->el_map.nfunc; i++)
283*0a6a1f1dSLionel Sambuc 		if (Strcmp(b[i].name, cmd) == 0)
284*0a6a1f1dSLionel Sambuc 			return b[i].func;
2853e1db26aSLionel Sambuc 	return -1;
2863e1db26aSLionel Sambuc }
287