1 /* $OpenBSD: parse.c,v 1.20 2016/04/11 21:17:29 schwarze Exp $ */ 2 /* $NetBSD: parse.c,v 1.38 2016/04/11 18:56:31 christos 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 "config.h" 37 38 /* 39 * parse.c: parse an editline extended command 40 * 41 * commands are: 42 * 43 * bind 44 * echotc 45 * edit 46 * gettc 47 * history 48 * settc 49 * setty 50 */ 51 #include <stdlib.h> 52 #include <string.h> 53 54 #include "el.h" 55 #include "parse.h" 56 57 static const struct { 58 const wchar_t *name; 59 int (*func)(EditLine *, int, const wchar_t **); 60 } cmds[] = { 61 { L"bind", map_bind }, 62 { L"echotc", terminal_echotc }, 63 { L"edit", el_editmode }, 64 { L"history", hist_command }, 65 { L"telltc", terminal_telltc }, 66 { L"settc", terminal_settc }, 67 { L"setty", tty_stty }, 68 { NULL, NULL } 69 }; 70 71 72 /* parse_line(): 73 * Parse a line and dispatch it 74 */ 75 protected int 76 parse_line(EditLine *el, const wchar_t *line) 77 { 78 const wchar_t **argv; 79 int argc; 80 TokenizerW *tok; 81 82 tok = tok_winit(NULL); 83 tok_wstr(tok, line, &argc, &argv); 84 argc = el_wparse(el, argc, argv); 85 tok_wend(tok); 86 return argc; 87 } 88 89 90 /* el_parse(): 91 * Command dispatcher 92 */ 93 int 94 el_wparse(EditLine *el, int argc, const wchar_t *argv[]) 95 { 96 const wchar_t *ptr; 97 int i; 98 99 if (argc < 1) 100 return -1; 101 ptr = wcschr(argv[0], L':'); 102 if (ptr != NULL) { 103 wchar_t *tprog; 104 size_t l; 105 106 if (ptr == argv[0]) 107 return 0; 108 l = ptr - argv[0] - 1; 109 tprog = reallocarray(NULL, l + 1, sizeof(*tprog)); 110 if (tprog == NULL) 111 return 0; 112 (void) wcsncpy(tprog, argv[0], l); 113 tprog[l] = '\0'; 114 ptr++; 115 l = el_match(el->el_prog, tprog); 116 free(tprog); 117 if (!l) 118 return 0; 119 } else 120 ptr = argv[0]; 121 122 for (i = 0; cmds[i].name != NULL; i++) 123 if (wcscmp(cmds[i].name, ptr) == 0) { 124 i = (*cmds[i].func) (el, argc, argv); 125 return -i; 126 } 127 return -1; 128 } 129 130 131 /* parse__escape(): 132 * Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return 133 * the appropriate character or -1 if the escape is not valid 134 */ 135 protected int 136 parse__escape(const wchar_t **ptr) 137 { 138 const wchar_t *p; 139 wint_t c; 140 141 p = *ptr; 142 143 if (p[1] == 0) 144 return -1; 145 146 if (*p == '\\') { 147 p++; 148 switch (*p) { 149 case 'a': 150 c = '\007'; /* Bell */ 151 break; 152 case 'b': 153 c = '\010'; /* Backspace */ 154 break; 155 case 't': 156 c = '\011'; /* Horizontal Tab */ 157 break; 158 case 'n': 159 c = '\012'; /* New Line */ 160 break; 161 case 'v': 162 c = '\013'; /* Vertical Tab */ 163 break; 164 case 'f': 165 c = '\014'; /* Form Feed */ 166 break; 167 case 'r': 168 c = '\015'; /* Carriage Return */ 169 break; 170 case 'e': 171 c = '\033'; /* Escape */ 172 break; 173 case 'U': /* Unicode \U+xxxx or \U+xxxxx format */ 174 { 175 int i; 176 const wchar_t hex[] = L"0123456789ABCDEF"; 177 const wchar_t *h; 178 ++p; 179 if (*p++ != '+') 180 return -1; 181 c = 0; 182 for (i = 0; i < 5; ++i) { 183 h = wcschr(hex, *p++); 184 if (!h && i < 4) 185 return -1; 186 else if (h) 187 c = (c << 4) | ((int)(h - hex)); 188 else 189 --p; 190 } 191 if (c > 0x10FFFF) /* outside valid character range */ 192 return -1; 193 break; 194 } 195 case '0': 196 case '1': 197 case '2': 198 case '3': 199 case '4': 200 case '5': 201 case '6': 202 case '7': 203 { 204 int cnt, ch; 205 206 for (cnt = 0, c = 0; cnt < 3; cnt++) { 207 ch = *p++; 208 if (ch < '0' || ch > '7') { 209 p--; 210 break; 211 } 212 c = (c << 3) | (ch - '0'); 213 } 214 if ((c & 0xffffff00) != 0) 215 return -1; 216 --p; 217 break; 218 } 219 default: 220 c = *p; 221 break; 222 } 223 } else if (*p == '^') { 224 p++; 225 c = (*p == '?') ? '\177' : (*p & 0237); 226 } else 227 c = *p; 228 *ptr = ++p; 229 return c; 230 } 231 232 /* parse__string(): 233 * Parse the escapes from in and put the raw string out 234 */ 235 protected wchar_t * 236 parse__string(wchar_t *out, const wchar_t *in) 237 { 238 wchar_t *rv = out; 239 int n; 240 241 for (;;) 242 switch (*in) { 243 case '\0': 244 *out = '\0'; 245 return rv; 246 247 case '\\': 248 case '^': 249 if ((n = parse__escape(&in)) == -1) 250 return NULL; 251 *out++ = (wchar_t)n; 252 break; 253 254 case 'M': 255 if (in[1] == '-' && in[2] != '\0') { 256 *out++ = '\033'; 257 in += 2; 258 break; 259 } 260 /*FALLTHROUGH*/ 261 262 default: 263 *out++ = *in++; 264 break; 265 } 266 } 267 268 269 /* parse_cmd(): 270 * Return the command number for the command string given 271 * or -1 if one is not found 272 */ 273 protected int 274 parse_cmd(EditLine *el, const wchar_t *cmd) 275 { 276 el_bindings_t *b; 277 int i; 278 279 for (b = el->el_map.help, i = 0; i < el->el_map.nfunc; i++) 280 if (wcscmp(b[i].name, cmd) == 0) 281 return b[i].func; 282 return -1; 283 } 284