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