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 38 static 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 63 static 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 */ 81 libedit_private int 82 parse_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 */ 99 int 100 el_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 */ 141 libedit_private int 142 parse__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 */ 241 libedit_private wchar_t * 242 parse__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 */ 279 libedit_private int 280 parse_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