1/* $NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 christos Exp $ */ 2 3/*- 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Christos Zoulas of Cornell University. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include "config.h" 36#if !defined(lint) && !defined(SCCSID) 37#if 0 38static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; 39#else 40__RCSID("$NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 christos Exp $"); 41#endif 42#endif /* not lint && not SCCSID */ 43 44/* 45 * parse.c: parse an editline extended command 46 * 47 * commands are: 48 * 49 * bind 50 * echotc 51 * edit 52 * gettc 53 * history 54 * settc 55 * setty 56 */ 57#include <stdlib.h> 58#include <string.h> 59 60#include "el.h" 61#include "parse.h" 62 63static const struct { 64 const wchar_t *name; 65 int (*func)(EditLine *, int, const wchar_t **); 66} cmds[] = { 67 { L"bind", map_bind }, 68 { L"echotc", terminal_echotc }, 69 { L"edit", el_editmode }, 70 { L"history", hist_command }, 71 { L"telltc", terminal_telltc }, 72 { L"settc", terminal_settc }, 73 { L"setty", tty_stty }, 74 { NULL, NULL } 75}; 76 77 78/* parse_line(): 79 * Parse a line and dispatch it 80 */ 81libedit_private int 82parse_line(EditLine *el, const wchar_t *line) 83{ 84 const wchar_t **argv; 85 int argc; 86 TokenizerW *tok; 87 88 tok = tok_winit(NULL); 89 tok_wstr(tok, line, &argc, &argv); 90 argc = el_wparse(el, argc, argv); 91 tok_wend(tok); 92 return argc; 93} 94 95 96/* el_parse(): 97 * Command dispatcher 98 */ 99int 100el_wparse(EditLine *el, int argc, const wchar_t *argv[]) 101{ 102 const wchar_t *ptr; 103 int i; 104 105 if (argc < 1) 106 return -1; 107 ptr = wcschr(argv[0], L':'); 108 if (ptr != NULL) { 109 wchar_t *tprog; 110 size_t l; 111 112 if (ptr == argv[0]) 113 return 0; 114 l = (size_t)(ptr - argv[0]); 115 tprog = el_calloc(l + 1, sizeof(*tprog)); 116 if (tprog == NULL) 117 return 0; 118 (void) wcsncpy(tprog, argv[0], l); 119 tprog[l] = '\0'; 120 ptr++; 121 l = (size_t)el_match(el->el_prog, tprog); 122 el_free(tprog); 123 if (!l) 124 return 0; 125 } else 126 ptr = argv[0]; 127 128 for (i = 0; cmds[i].name != NULL; i++) 129 if (wcscmp(cmds[i].name, ptr) == 0) { 130 i = (*cmds[i].func) (el, argc, argv); 131 return -i; 132 } 133 return -1; 134} 135 136 137/* parse__escape(): 138 * Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return 139 * the appropriate character or -1 if the escape is not valid 140 */ 141libedit_private int 142parse__escape(const wchar_t **ptr) 143{ 144 const wchar_t *p; 145 wint_t c; 146 147 p = *ptr; 148 149 if (p[1] == 0) 150 return -1; 151 152 if (*p == '\\') { 153 p++; 154 switch (*p) { 155 case 'a': 156 c = '\007'; /* Bell */ 157 break; 158 case 'b': 159 c = '\010'; /* Backspace */ 160 break; 161 case 't': 162 c = '\011'; /* Horizontal Tab */ 163 break; 164 case 'n': 165 c = '\012'; /* New Line */ 166 break; 167 case 'v': 168 c = '\013'; /* Vertical Tab */ 169 break; 170 case 'f': 171 c = '\014'; /* Form Feed */ 172 break; 173 case 'r': 174 c = '\015'; /* Carriage Return */ 175 break; 176 case 'e': 177 c = '\033'; /* Escape */ 178 break; 179 case 'U': /* Unicode \U+xxxx or \U+xxxxx format */ 180 { 181 int i; 182 const wchar_t hex[] = L"0123456789ABCDEF"; 183 const wchar_t *h; 184 ++p; 185 if (*p++ != '+') 186 return -1; 187 c = 0; 188 for (i = 0; i < 5; ++i) { 189 h = wcschr(hex, *p++); 190 if (!h && i < 4) 191 return -1; 192 else if (h) 193 c = (c << 4) | ((int)(h - hex)); 194 else 195 --p; 196 } 197 if (c > 0x10FFFF) /* outside valid character range */ 198 return -1; 199 break; 200 } 201 case '0': 202 case '1': 203 case '2': 204 case '3': 205 case '4': 206 case '5': 207 case '6': 208 case '7': 209 { 210 int cnt, ch; 211 212 for (cnt = 0, c = 0; cnt < 3; cnt++) { 213 ch = *p++; 214 if (ch < '0' || ch > '7') { 215 p--; 216 break; 217 } 218 c = (c << 3) | (ch - '0'); 219 } 220 if ((c & (wint_t)0xffffff00) != (wint_t)0) 221 return -1; 222 --p; 223 break; 224 } 225 default: 226 c = *p; 227 break; 228 } 229 } else if (*p == '^') { 230 p++; 231 c = (*p == '?') ? '\177' : (*p & 0237); 232 } else 233 c = *p; 234 *ptr = ++p; 235 return c; 236} 237 238/* parse__string(): 239 * Parse the escapes from in and put the raw string out 240 */ 241libedit_private wchar_t * 242parse__string(wchar_t *out, const wchar_t *in) 243{ 244 wchar_t *rv = out; 245 int n; 246 247 for (;;) 248 switch (*in) { 249 case '\0': 250 *out = '\0'; 251 return rv; 252 253 case '\\': 254 case '^': 255 if ((n = parse__escape(&in)) == -1) 256 return NULL; 257 *out++ = (wchar_t)n; 258 break; 259 260 case 'M': 261 if (in[1] == '-' && in[2] != '\0') { 262 *out++ = '\033'; 263 in += 2; 264 break; 265 } 266 /*FALLTHROUGH*/ 267 268 default: 269 *out++ = *in++; 270 break; 271 } 272} 273 274 275/* parse_cmd(): 276 * Return the command number for the command string given 277 * or -1 if one is not found 278 */ 279libedit_private int 280parse_cmd(EditLine *el, const wchar_t *cmd) 281{ 282 el_bindings_t *b = el->el_map.help; 283 size_t i; 284 285 for (i = 0; i < el->el_map.nfunc; i++) 286 if (wcscmp(b[i].name, cmd) == 0) 287 return b[i].func; 288 return -1; 289} 290