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