1*ae19eda8Szrj /* $NetBSD: parse.c,v 1.41 2018/11/29 03:10:20 christos Exp $ */ 232fe07f8SJohn Marino 332fe07f8SJohn Marino /*- 432fe07f8SJohn Marino * Copyright (c) 1992, 1993 532fe07f8SJohn Marino * The Regents of the University of California. All rights reserved. 632fe07f8SJohn Marino * 732fe07f8SJohn Marino * This code is derived from software contributed to Berkeley by 832fe07f8SJohn Marino * Christos Zoulas of Cornell University. 932fe07f8SJohn Marino * 1032fe07f8SJohn Marino * Redistribution and use in source and binary forms, with or without 1132fe07f8SJohn Marino * modification, are permitted provided that the following conditions 1232fe07f8SJohn Marino * are met: 1332fe07f8SJohn Marino * 1. Redistributions of source code must retain the above copyright 1432fe07f8SJohn Marino * notice, this list of conditions and the following disclaimer. 1532fe07f8SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright 1632fe07f8SJohn Marino * notice, this list of conditions and the following disclaimer in the 1732fe07f8SJohn Marino * documentation and/or other materials provided with the distribution. 1832fe07f8SJohn Marino * 3. Neither the name of the University nor the names of its contributors 1932fe07f8SJohn Marino * may be used to endorse or promote products derived from this software 2032fe07f8SJohn Marino * without specific prior written permission. 2132fe07f8SJohn Marino * 2232fe07f8SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2332fe07f8SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2432fe07f8SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2532fe07f8SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2632fe07f8SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2732fe07f8SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2832fe07f8SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2932fe07f8SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3032fe07f8SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3132fe07f8SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3232fe07f8SJohn Marino * SUCH DAMAGE. 3332fe07f8SJohn Marino */ 3432fe07f8SJohn Marino 3532fe07f8SJohn Marino #include "config.h" 3632fe07f8SJohn Marino #if !defined(lint) && !defined(SCCSID) 3732fe07f8SJohn Marino #if 0 3832fe07f8SJohn Marino static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; 3932fe07f8SJohn Marino #else 40*ae19eda8Szrj __RCSID("$NetBSD: parse.c,v 1.41 2018/11/29 03:10:20 christos Exp $"); 4132fe07f8SJohn Marino #endif 4232fe07f8SJohn Marino #endif /* not lint && not SCCSID */ 4332fe07f8SJohn Marino 4432fe07f8SJohn Marino /* 4532fe07f8SJohn Marino * parse.c: parse an editline extended command 4632fe07f8SJohn Marino * 4732fe07f8SJohn Marino * commands are: 4832fe07f8SJohn Marino * 4932fe07f8SJohn Marino * bind 5032fe07f8SJohn Marino * echotc 5132fe07f8SJohn Marino * edit 5232fe07f8SJohn Marino * gettc 5332fe07f8SJohn Marino * history 5432fe07f8SJohn Marino * settc 5532fe07f8SJohn Marino * setty 5632fe07f8SJohn Marino */ 5732fe07f8SJohn Marino #include <stdlib.h> 5812db70c8Szrj #include <string.h> 5932fe07f8SJohn Marino 6012db70c8Szrj #include "el.h" 6112db70c8Szrj #include "parse.h" 6212db70c8Szrj 6312db70c8Szrj static const struct { 6412db70c8Szrj const wchar_t *name; 6512db70c8Szrj int (*func)(EditLine *, int, const wchar_t **); 6632fe07f8SJohn Marino } cmds[] = { 6712db70c8Szrj { L"bind", map_bind }, 6812db70c8Szrj { L"echotc", terminal_echotc }, 6912db70c8Szrj { L"edit", el_editmode }, 7012db70c8Szrj { L"history", hist_command }, 7112db70c8Szrj { L"telltc", terminal_telltc }, 7212db70c8Szrj { L"settc", terminal_settc }, 7312db70c8Szrj { L"setty", tty_stty }, 7432fe07f8SJohn Marino { NULL, NULL } 7532fe07f8SJohn Marino }; 7632fe07f8SJohn Marino 7732fe07f8SJohn Marino 7832fe07f8SJohn Marino /* parse_line(): 7932fe07f8SJohn Marino * Parse a line and dispatch it 8032fe07f8SJohn Marino */ 8112db70c8Szrj libedit_private int 8212db70c8Szrj parse_line(EditLine *el, const wchar_t *line) 8332fe07f8SJohn Marino { 8412db70c8Szrj const wchar_t **argv; 8532fe07f8SJohn Marino int argc; 8612db70c8Szrj TokenizerW *tok; 8732fe07f8SJohn Marino 8812db70c8Szrj tok = tok_winit(NULL); 8912db70c8Szrj tok_wstr(tok, line, &argc, &argv); 9012db70c8Szrj argc = el_wparse(el, argc, argv); 9112db70c8Szrj tok_wend(tok); 9232fe07f8SJohn Marino return argc; 9332fe07f8SJohn Marino } 9432fe07f8SJohn Marino 9532fe07f8SJohn Marino 9632fe07f8SJohn Marino /* el_parse(): 9732fe07f8SJohn Marino * Command dispatcher 9832fe07f8SJohn Marino */ 9912db70c8Szrj int 10012db70c8Szrj el_wparse(EditLine *el, int argc, const wchar_t *argv[]) 10132fe07f8SJohn Marino { 10212db70c8Szrj const wchar_t *ptr; 10332fe07f8SJohn Marino int i; 10432fe07f8SJohn Marino 10532fe07f8SJohn Marino if (argc < 1) 10632fe07f8SJohn Marino return -1; 10712db70c8Szrj ptr = wcschr(argv[0], L':'); 10832fe07f8SJohn Marino if (ptr != NULL) { 10912db70c8Szrj wchar_t *tprog; 11032fe07f8SJohn Marino size_t l; 11132fe07f8SJohn Marino 11232fe07f8SJohn Marino if (ptr == argv[0]) 11332fe07f8SJohn Marino return 0; 114*ae19eda8Szrj l = (size_t)(ptr - argv[0]); 11532fe07f8SJohn Marino tprog = el_malloc((l + 1) * sizeof(*tprog)); 11632fe07f8SJohn Marino if (tprog == NULL) 11732fe07f8SJohn Marino return 0; 11812db70c8Szrj (void) wcsncpy(tprog, argv[0], l); 11932fe07f8SJohn Marino tprog[l] = '\0'; 12032fe07f8SJohn Marino ptr++; 12132fe07f8SJohn Marino l = (size_t)el_match(el->el_prog, tprog); 12232fe07f8SJohn Marino el_free(tprog); 12332fe07f8SJohn Marino if (!l) 12432fe07f8SJohn Marino return 0; 12532fe07f8SJohn Marino } else 12632fe07f8SJohn Marino ptr = argv[0]; 12732fe07f8SJohn Marino 12832fe07f8SJohn Marino for (i = 0; cmds[i].name != NULL; i++) 12912db70c8Szrj if (wcscmp(cmds[i].name, ptr) == 0) { 13032fe07f8SJohn Marino i = (*cmds[i].func) (el, argc, argv); 13132fe07f8SJohn Marino return -i; 13232fe07f8SJohn Marino } 13332fe07f8SJohn Marino return -1; 13432fe07f8SJohn Marino } 13532fe07f8SJohn Marino 13632fe07f8SJohn Marino 13732fe07f8SJohn Marino /* parse__escape(): 13832fe07f8SJohn Marino * Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return 13932fe07f8SJohn Marino * the appropriate character or -1 if the escape is not valid 14032fe07f8SJohn Marino */ 14112db70c8Szrj libedit_private int 14212db70c8Szrj parse__escape(const wchar_t **ptr) 14332fe07f8SJohn Marino { 14412db70c8Szrj const wchar_t *p; 14512db70c8Szrj wint_t c; 14632fe07f8SJohn Marino 14732fe07f8SJohn Marino p = *ptr; 14832fe07f8SJohn Marino 14932fe07f8SJohn Marino if (p[1] == 0) 15032fe07f8SJohn Marino return -1; 15132fe07f8SJohn Marino 15232fe07f8SJohn Marino if (*p == '\\') { 15332fe07f8SJohn Marino p++; 15432fe07f8SJohn Marino switch (*p) { 15532fe07f8SJohn Marino case 'a': 15632fe07f8SJohn Marino c = '\007'; /* Bell */ 15732fe07f8SJohn Marino break; 15832fe07f8SJohn Marino case 'b': 15932fe07f8SJohn Marino c = '\010'; /* Backspace */ 16032fe07f8SJohn Marino break; 16132fe07f8SJohn Marino case 't': 16232fe07f8SJohn Marino c = '\011'; /* Horizontal Tab */ 16332fe07f8SJohn Marino break; 16432fe07f8SJohn Marino case 'n': 16532fe07f8SJohn Marino c = '\012'; /* New Line */ 16632fe07f8SJohn Marino break; 16732fe07f8SJohn Marino case 'v': 16832fe07f8SJohn Marino c = '\013'; /* Vertical Tab */ 16932fe07f8SJohn Marino break; 17032fe07f8SJohn Marino case 'f': 17132fe07f8SJohn Marino c = '\014'; /* Form Feed */ 17232fe07f8SJohn Marino break; 17332fe07f8SJohn Marino case 'r': 17432fe07f8SJohn Marino c = '\015'; /* Carriage Return */ 17532fe07f8SJohn Marino break; 17632fe07f8SJohn Marino case 'e': 17732fe07f8SJohn Marino c = '\033'; /* Escape */ 17832fe07f8SJohn Marino break; 17932fe07f8SJohn Marino case 'U': /* Unicode \U+xxxx or \U+xxxxx format */ 18032fe07f8SJohn Marino { 18132fe07f8SJohn Marino int i; 18212db70c8Szrj const wchar_t hex[] = L"0123456789ABCDEF"; 18312db70c8Szrj const wchar_t *h; 18432fe07f8SJohn Marino ++p; 18532fe07f8SJohn Marino if (*p++ != '+') 18632fe07f8SJohn Marino return -1; 18732fe07f8SJohn Marino c = 0; 18832fe07f8SJohn Marino for (i = 0; i < 5; ++i) { 18912db70c8Szrj h = wcschr(hex, *p++); 19032fe07f8SJohn Marino if (!h && i < 4) 19132fe07f8SJohn Marino return -1; 19232fe07f8SJohn Marino else if (h) 19332fe07f8SJohn Marino c = (c << 4) | ((int)(h - hex)); 19432fe07f8SJohn Marino else 19532fe07f8SJohn Marino --p; 19632fe07f8SJohn Marino } 19732fe07f8SJohn Marino if (c > 0x10FFFF) /* outside valid character range */ 19832fe07f8SJohn Marino return -1; 19932fe07f8SJohn Marino break; 20032fe07f8SJohn Marino } 20132fe07f8SJohn Marino case '0': 20232fe07f8SJohn Marino case '1': 20332fe07f8SJohn Marino case '2': 20432fe07f8SJohn Marino case '3': 20532fe07f8SJohn Marino case '4': 20632fe07f8SJohn Marino case '5': 20732fe07f8SJohn Marino case '6': 20832fe07f8SJohn Marino case '7': 20932fe07f8SJohn Marino { 21032fe07f8SJohn Marino int cnt, ch; 21132fe07f8SJohn Marino 21232fe07f8SJohn Marino for (cnt = 0, c = 0; cnt < 3; cnt++) { 21332fe07f8SJohn Marino ch = *p++; 21432fe07f8SJohn Marino if (ch < '0' || ch > '7') { 21532fe07f8SJohn Marino p--; 21632fe07f8SJohn Marino break; 21732fe07f8SJohn Marino } 21832fe07f8SJohn Marino c = (c << 3) | (ch - '0'); 21932fe07f8SJohn Marino } 22032fe07f8SJohn Marino if ((c & (wint_t)0xffffff00) != (wint_t)0) 22132fe07f8SJohn Marino return -1; 22232fe07f8SJohn Marino --p; 22332fe07f8SJohn Marino break; 22432fe07f8SJohn Marino } 22532fe07f8SJohn Marino default: 22632fe07f8SJohn Marino c = *p; 22732fe07f8SJohn Marino break; 22832fe07f8SJohn Marino } 22932fe07f8SJohn Marino } else if (*p == '^') { 23032fe07f8SJohn Marino p++; 23132fe07f8SJohn Marino c = (*p == '?') ? '\177' : (*p & 0237); 23232fe07f8SJohn Marino } else 23332fe07f8SJohn Marino c = *p; 23432fe07f8SJohn Marino *ptr = ++p; 23532fe07f8SJohn Marino return c; 23632fe07f8SJohn Marino } 23732fe07f8SJohn Marino 23832fe07f8SJohn Marino /* parse__string(): 23932fe07f8SJohn Marino * Parse the escapes from in and put the raw string out 24032fe07f8SJohn Marino */ 24112db70c8Szrj libedit_private wchar_t * 24212db70c8Szrj parse__string(wchar_t *out, const wchar_t *in) 24332fe07f8SJohn Marino { 24412db70c8Szrj wchar_t *rv = out; 24532fe07f8SJohn Marino int n; 24632fe07f8SJohn Marino 24732fe07f8SJohn Marino for (;;) 24832fe07f8SJohn Marino switch (*in) { 24932fe07f8SJohn Marino case '\0': 25032fe07f8SJohn Marino *out = '\0'; 25132fe07f8SJohn Marino return rv; 25232fe07f8SJohn Marino 25332fe07f8SJohn Marino case '\\': 25432fe07f8SJohn Marino case '^': 25532fe07f8SJohn Marino if ((n = parse__escape(&in)) == -1) 25632fe07f8SJohn Marino return NULL; 25712db70c8Szrj *out++ = (wchar_t)n; 25832fe07f8SJohn Marino break; 25932fe07f8SJohn Marino 26032fe07f8SJohn Marino case 'M': 26132fe07f8SJohn Marino if (in[1] == '-' && in[2] != '\0') { 26232fe07f8SJohn Marino *out++ = '\033'; 26332fe07f8SJohn Marino in += 2; 26432fe07f8SJohn Marino break; 26532fe07f8SJohn Marino } 26632fe07f8SJohn Marino /*FALLTHROUGH*/ 26732fe07f8SJohn Marino 26832fe07f8SJohn Marino default: 26932fe07f8SJohn Marino *out++ = *in++; 27032fe07f8SJohn Marino break; 27132fe07f8SJohn Marino } 27232fe07f8SJohn Marino } 27332fe07f8SJohn Marino 27432fe07f8SJohn Marino 27532fe07f8SJohn Marino /* parse_cmd(): 27632fe07f8SJohn Marino * Return the command number for the command string given 27732fe07f8SJohn Marino * or -1 if one is not found 27832fe07f8SJohn Marino */ 27912db70c8Szrj libedit_private int 28012db70c8Szrj parse_cmd(EditLine *el, const wchar_t *cmd) 28132fe07f8SJohn Marino { 282a0c9eb18SJohn Marino el_bindings_t *b = el->el_map.help; 283a0c9eb18SJohn Marino size_t i; 28432fe07f8SJohn Marino 285a0c9eb18SJohn Marino for (i = 0; i < el->el_map.nfunc; i++) 28612db70c8Szrj if (wcscmp(b[i].name, cmd) == 0) 287a0c9eb18SJohn Marino return b[i].func; 28832fe07f8SJohn Marino return -1; 28932fe07f8SJohn Marino } 290