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