1/*	$NetBSD: parse.c,v 1.6 2005/06/09 16:48:58 lukem Exp $	*/
2/*	from	NetBSD: parse.c,v 1.22 2005/05/29 04:58:15 lukem Exp	*/
3
4/*-
5 * Copyright (c) 1992, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
10 *
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.
22 *
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.
34 */
35
36#include "tnftp.h"
37#include "sys.h"
38
39/*
40 * parse.c: parse an editline extended command
41 *
42 * commands are:
43 *
44 *	bind
45 *	echotc
46 *	edit
47 *	gettc
48 *	history
49 *	settc
50 *	setty
51 */
52#include "el.h"
53#include <stdlib.h>
54
55private const struct {
56	const char *name;
57	int (*func)(EditLine *, int, const char **);
58} cmds[] = {
59	{ "bind",	map_bind	},
60	{ "echotc",	term_echotc	},
61	{ "edit",	el_editmode	},
62	{ "history",	hist_command	},
63	{ "telltc",	term_telltc	},
64	{ "settc",	term_settc	},
65	{ "setty",	tty_stty	},
66	{ NULL,		NULL		}
67};
68
69
70/* parse_line():
71 *	Parse a line and dispatch it
72 */
73protected int
74parse_line(EditLine *el, const char *line)
75{
76	const char **argv;
77	int argc;
78	Tokenizer *tok;
79
80	tok = tok_init(NULL);
81	tok_str(tok, line, &argc, &argv);
82	argc = el_parse(el, argc, argv);
83	tok_end(tok);
84	return (argc);
85}
86
87
88/* el_parse():
89 *	Command dispatcher
90 */
91public int
92el_parse(EditLine *el, int argc, const char *argv[])
93{
94	const char *ptr;
95	int i;
96
97	if (argc < 1)
98		return (-1);
99	ptr = strchr(argv[0], ':');
100	if (ptr != NULL) {
101		char *tprog;
102		size_t l;
103
104		if (ptr == argv[0])
105			return (0);
106		l = ptr - argv[0] - 1;
107		tprog = (char *) el_malloc(l + 1);
108		if (tprog == NULL)
109			return (0);
110		(void) strncpy(tprog, argv[0], l);
111		tprog[l] = '\0';
112		ptr++;
113		l = el_match(el->el_prog, tprog);
114		el_free(tprog);
115		if (!l)
116			return (0);
117	} else
118		ptr = argv[0];
119
120	for (i = 0; cmds[i].name != NULL; i++)
121		if (strcmp(cmds[i].name, ptr) == 0) {
122			i = (*cmds[i].func) (el, argc, argv);
123			return (-i);
124		}
125	return (-1);
126}
127
128
129/* parse__escape():
130 *	Parse a string of the form ^<char> \<odigit> \<char> and return
131 *	the appropriate character or -1 if the escape is not valid
132 */
133protected int
134parse__escape(const char **ptr)
135{
136	const char *p;
137	int c;
138
139	p = *ptr;
140
141	if (p[1] == 0)
142		return (-1);
143
144	if (*p == '\\') {
145		p++;
146		switch (*p) {
147		case 'a':
148			c = '\007';	/* Bell */
149			break;
150		case 'b':
151			c = '\010';	/* Backspace */
152			break;
153		case 't':
154			c = '\011';	/* Horizontal Tab */
155			break;
156		case 'n':
157			c = '\012';	/* New Line */
158			break;
159		case 'v':
160			c = '\013';	/* Vertical Tab */
161			break;
162		case 'f':
163			c = '\014';	/* Form Feed */
164			break;
165		case 'r':
166			c = '\015';	/* Carriage Return */
167			break;
168		case 'e':
169			c = '\033';	/* Escape */
170			break;
171		case '0':
172		case '1':
173		case '2':
174		case '3':
175		case '4':
176		case '5':
177		case '6':
178		case '7':
179		{
180			int cnt, ch;
181
182			for (cnt = 0, c = 0; cnt < 3; cnt++) {
183				ch = *p++;
184				if (ch < '0' || ch > '7') {
185					p--;
186					break;
187				}
188				c = (c << 3) | (ch - '0');
189			}
190			if ((c & 0xffffff00) != 0)
191				return (-1);
192			--p;
193			break;
194		}
195		default:
196			c = *p;
197			break;
198		}
199	} else if (*p == '^') {
200		p++;
201		c = (*p == '?') ? '\177' : (*p & 0237);
202	} else
203		c = *p;
204	*ptr = ++p;
205	return (c);
206}
207
208/* parse__string():
209 *	Parse the escapes from in and put the raw string out
210 */
211protected char *
212parse__string(char *out, const char *in)
213{
214	char *rv = out;
215	int n;
216
217	for (;;)
218		switch (*in) {
219		case '\0':
220			*out = '\0';
221			return (rv);
222
223		case '\\':
224		case '^':
225			if ((n = parse__escape(&in)) == -1)
226				return (NULL);
227			*out++ = n;
228			break;
229
230		case 'M':
231			if (in[1] == '-' && in[2] != '\0') {
232				*out++ = '\033';
233				in += 2;
234				break;
235			}
236			/*FALLTHROUGH*/
237
238		default:
239			*out++ = *in++;
240			break;
241		}
242}
243
244
245/* parse_cmd():
246 *	Return the command number for the command string given
247 *	or -1 if one is not found
248 */
249protected int
250parse_cmd(EditLine *el, const char *cmd)
251{
252	el_bindings_t *b;
253
254	for (b = el->el_map.help; b->name != NULL; b++)
255		if (strcmp(b->name, cmd) == 0)
256			return (b->func);
257	return (-1);
258}
259