diff options
Diffstat (limited to 'contrib/less/lesskey_parse.c')
-rw-r--r-- | contrib/less/lesskey_parse.c | 295 |
1 files changed, 183 insertions, 112 deletions
diff --git a/contrib/less/lesskey_parse.c b/contrib/less/lesskey_parse.c index 18cdf3753d53..3f528aa8780a 100644 --- a/contrib/less/lesskey_parse.c +++ b/contrib/less/lesskey_parse.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1984-2021 Mark Nudelman + * Copyright (C) 1984-2023 Mark Nudelman * * You may distribute under the terms of either the GNU General Public * License or the Less License, as specified in the README file. @@ -7,13 +7,13 @@ * For more information, see the README file. */ +#include "defines.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include "lesskey.h" #include "cmd.h" #include "xbuf.h" -#include "defines.h" #define CONTROL(c) ((c)&037) #define ESC CONTROL('[') @@ -21,9 +21,12 @@ extern void lesskey_parse_error(char *msg); extern char *homefile(char *filename); extern void *ecalloc(int count, unsigned int size); +extern int lstrtoi(char *str, char **end, int radix); +extern char version[]; static int linenum; static int errors; +static int less_version = 0; static char *lesskey_file; static struct lesskey_cmdname cmdnames[] = @@ -85,6 +88,7 @@ static struct lesskey_cmdname cmdnames[] = { "set-mark", A_SETMARK }, { "set-mark-bottom", A_SETMARKBOT }, { "shell", A_SHELL }, + { "pshell", A_PSHELL }, { "status", A_STAT }, { "toggle-flag", A_OPT_TOGGLE }, { "toggle-option", A_OPT_TOGGLE }, @@ -123,23 +127,20 @@ static struct lesskey_cmdname editnames[] = /* * Print a parse error message. */ - static void -parse_error(s1, s2) - char *s1; - char *s2; +static void parse_error(char *fmt, char *arg1) { char buf[1024]; + int n = snprintf(buf, sizeof(buf), "%s: line %d: ", lesskey_file, linenum); + if (n >= 0 && n < sizeof(buf)) + snprintf(buf+n, sizeof(buf)-n, fmt, arg1); ++errors; - snprintf(buf, sizeof(buf), "%s: line %d: %s%s", lesskey_file, linenum, s1, s2); lesskey_parse_error(buf); } /* * Initialize lesskey_tables. */ - static void -init_tables(tables) - struct lesskey_tables *tables; +static void init_tables(struct lesskey_tables *tables) { tables->currtable = &tables->cmdtable; @@ -156,18 +157,40 @@ init_tables(tables) xbuf_init(&tables->vartable.buf); } +#define CHAR_STRING_LEN 8 + +static char * char_string(char *buf, int ch, int lit) +{ + if (lit || (ch >= 0x20 && ch < 0x7f)) + { + buf[0] = ch; + buf[1] = '\0'; + } else + { + snprintf(buf, CHAR_STRING_LEN, "\\x%02x", ch); + } + return buf; +} + +/* + * Increment char pointer by one up to terminating nul byte. + */ +static char * increment_pointer(char *p) +{ + if (*p == '\0') + return p; + return p+1; +} + /* * Parse one character of a string. */ - static char * -tstr(pp, xlate) - char **pp; - int xlate; +static char * tstr(char **pp, int xlate) { char *p; char ch; int i; - static char buf[10]; + static char buf[CHAR_STRING_LEN]; static char tstr_control_k[] = { SK_SPECIAL_KEY, SK_CONTROL_K, 6, 1, 1, 1, '\0' }; @@ -191,17 +214,13 @@ tstr(pp, xlate) *pp = p; if (xlate && ch == CONTROL('K')) return tstr_control_k; - buf[0] = ch; - buf[1] = '\0'; - return (buf); + return char_string(buf, ch, 1); case 'b': *pp = p+1; return ("\b"); case 'e': *pp = p+1; - buf[0] = ESC; - buf[1] = '\0'; - return (buf); + return char_string(buf, ESC, 1); case 'n': *pp = p+1; return ("\n"); @@ -216,19 +235,27 @@ tstr(pp, xlate) { switch (*++p) { - case 'u': ch = SK_UP_ARROW; break; + case 'b': ch = SK_BACKSPACE; break; + case 'B': ch = SK_CTL_BACKSPACE; break; case 'd': ch = SK_DOWN_ARROW; break; - case 'r': ch = SK_RIGHT_ARROW; break; - case 'l': ch = SK_LEFT_ARROW; break; - case 'U': ch = SK_PAGE_UP; break; case 'D': ch = SK_PAGE_DOWN; break; - case 'h': ch = SK_HOME; break; case 'e': ch = SK_END; break; + case 'h': ch = SK_HOME; break; + case 'i': ch = SK_INSERT; break; + case 'l': ch = SK_LEFT_ARROW; break; + case 'L': ch = SK_CTL_LEFT_ARROW; break; + case 'r': ch = SK_RIGHT_ARROW; break; + case 'R': ch = SK_CTL_RIGHT_ARROW; break; + case 't': ch = SK_BACKTAB; break; + case 'u': ch = SK_UP_ARROW; break; + case 'U': ch = SK_PAGE_UP; break; case 'x': ch = SK_DELETE; break; - default: { char buf[2]; buf[0] = *p; buf[1] = '\0'; - parse_error("illegal escape sequence \\k", buf); - *pp = p+1; - return (""); } + case 'X': ch = SK_CTL_DELETE; break; + case '1': ch = SK_F1; break; + default: + parse_error("invalid escape sequence \"\\k%s\"", char_string(buf, *p, 0)); + *pp = increment_pointer(p); + return (""); } *pp = p+1; buf[0] = SK_SPECIAL_KEY; @@ -246,9 +273,8 @@ tstr(pp, xlate) * Backslash followed by any other char * just means that char. */ - *pp = p+1; - buf[0] = *p; - buf[1] = '\0'; + *pp = increment_pointer(p); + char_string(buf, *p, 1); if (xlate && buf[0] == CONTROL('K')) return tstr_control_k; return (buf); @@ -257,24 +283,20 @@ tstr(pp, xlate) /* * Caret means CONTROL. */ - *pp = p+2; - buf[0] = CONTROL(p[1]); - buf[1] = '\0'; + *pp = increment_pointer(p+1); + char_string(buf, CONTROL(p[1]), 1); if (xlate && buf[0] == CONTROL('K')) return tstr_control_k; return (buf); } - *pp = p+1; - buf[0] = *p; - buf[1] = '\0'; + *pp = increment_pointer(p); + char_string(buf, *p, 1); if (xlate && buf[0] == CONTROL('K')) return tstr_control_k; return (buf); } - static int -issp(ch) - char ch; +static int issp(char ch) { return (ch == ' ' || ch == '\t'); } @@ -282,9 +304,7 @@ issp(ch) /* * Skip leading spaces in a string. */ - static char * -skipsp(s) - char *s; +static char * skipsp(char *s) { while (issp(*s)) s++; @@ -294,9 +314,7 @@ skipsp(s) /* * Skip non-space characters in a string. */ - static char * -skipnsp(s) - char *s; +static char * skipnsp(char *s) { while (*s != '\0' && !issp(*s)) s++; @@ -307,9 +325,7 @@ skipnsp(s) * Clean up an input line: * strip off the trailing newline & any trailing # comment. */ - static char * -clean_line(s) - char *s; +static char * clean_line(char *s) { int i; @@ -324,74 +340,127 @@ clean_line(s) /* * Add a byte to the output command table. */ - static void -add_cmd_char(c, tables) - int c; - struct lesskey_tables *tables; +static void add_cmd_char(unsigned char c, struct lesskey_tables *tables) +{ + xbuf_add_byte(&tables->currtable->buf, c); +} + +static void erase_cmd_char(struct lesskey_tables *tables) { - xbuf_add(&tables->currtable->buf, c); + xbuf_pop(&tables->currtable->buf); } /* * Add a string to the output command table. */ - static void -add_cmd_str(s, tables) - char *s; - struct lesskey_tables *tables; +static void add_cmd_str(char *s, struct lesskey_tables *tables) { for ( ; *s != '\0'; s++) add_cmd_char(*s, tables); } /* + * Does a given version number match the running version? + * Operator compares the running version to the given version. + */ +static int match_version(char op, int ver) +{ + switch (op) + { + case '>': return less_version > ver; + case '<': return less_version < ver; + case '+': return less_version >= ver; + case '-': return less_version <= ver; + case '=': return less_version == ver; + case '!': return less_version != ver; + default: return 0; /* cannot happen */ + } +} + +/* + * Handle a #version line. + * If the version matches, return the part of the line that should be executed. + * Otherwise, return NULL. + */ +static char * version_line(char *s, struct lesskey_tables *tables) +{ + char op; + int ver; + char *e; + char buf[CHAR_STRING_LEN]; + + s += strlen("#version"); + s = skipsp(s); + op = *s++; + /* Simplify 2-char op to one char. */ + switch (op) + { + case '<': if (*s == '=') { s++; op = '-'; } break; + case '>': if (*s == '=') { s++; op = '+'; } break; + case '=': if (*s == '=') { s++; } break; + case '!': if (*s == '=') { s++; } break; + default: + parse_error("invalid operator '%s' in #version line", char_string(buf, op, 0)); + return (NULL); + } + s = skipsp(s); + ver = lstrtoi(s, &e, 10); + if (e == s) + { + parse_error("non-numeric version number in #version line", ""); + return (NULL); + } + if (!match_version(op, ver)) + return (NULL); + return (e); +} + +/* * See if we have a special "control" line. */ - static int -control_line(s, tables) - char *s; - struct lesskey_tables *tables; +static char * control_line(char *s, struct lesskey_tables *tables) { #define PREFIX(str,pat) (strncmp(str,pat,strlen(pat)) == 0) if (PREFIX(s, "#line-edit")) { tables->currtable = &tables->edittable; - return (1); + return (NULL); } if (PREFIX(s, "#command")) { tables->currtable = &tables->cmdtable; - return (1); + return (NULL); } if (PREFIX(s, "#env")) { tables->currtable = &tables->vartable; - return (1); + return (NULL); } if (PREFIX(s, "#stop")) { add_cmd_char('\0', tables); add_cmd_char(A_END_LIST, tables); - return (1); + return (NULL); } - return (0); + if (PREFIX(s, "#version")) + { + return (version_line(s, tables)); + } + return (s); } /* * Find an action, given the name of the action. */ - static int -findaction(actname, tables) - char *actname; - struct lesskey_tables *tables; +static int findaction(char *actname, struct lesskey_tables *tables) { int i; for (i = 0; tables->currtable->names[i].cn_name != NULL; i++) if (strcmp(tables->currtable->names[i].cn_name, actname) == 0) return (tables->currtable->names[i].cn_action); - parse_error("unknown action: ", actname); + parse_error("unknown action: \"%s\"", actname); return (A_INVALID); } @@ -402,10 +471,7 @@ findaction(actname, tables) * resulting less action, and EXTRA is an "extra" user * key sequence injected after the action. */ - static void -parse_cmdline(p, tables) - char *p; - struct lesskey_tables *tables; +static void parse_cmdline(char *p, struct lesskey_tables *tables) { char *actname; int action; @@ -453,14 +519,14 @@ parse_cmdline(p, tables) p = skipsp(p); if (*p == '\0') { - add_cmd_char(action, tables); + add_cmd_char((unsigned char) action, tables); } else { /* * OR the special value A_EXTRA into the action byte. * Put the extra string after the action byte. */ - add_cmd_char(action | A_EXTRA, tables); + add_cmd_char((unsigned char) (action | A_EXTRA), tables); while (*p != '\0') add_cmd_str(tstr(&p, 0), tables); add_cmd_char('\0', tables); @@ -471,33 +537,41 @@ parse_cmdline(p, tables) * Parse a variable definition line, of the form * NAME = VALUE */ - static void -parse_varline(line, tables) - char *line; - struct lesskey_tables *tables; +static void parse_varline(char *line, struct lesskey_tables *tables) { char *s; char *p = line; + char *eq; - do + eq = strchr(line, '='); + if (eq != NULL && eq > line && eq[-1] == '+') { - s = tstr(&p, 0); - add_cmd_str(s, tables); - } while (*p != '\0' && !issp(*p) && *p != '='); - /* - * Terminate the variable name with a null byte. - */ - add_cmd_char('\0', tables); - - p = skipsp(p); - if (*p++ != '=') + /* + * Rather ugly way of handling a += line. + * {{ Note that we ignore the variable name and + * just append to the previously defined variable. }} + */ + erase_cmd_char(tables); /* backspace over the final null */ + p = eq+1; + } else { - parse_error("missing = in: ", line); - return; + do + { + s = tstr(&p, 0); + add_cmd_str(s, tables); + } while (*p != '\0' && !issp(*p) && *p != '='); + /* + * Terminate the variable name with a null byte. + */ + add_cmd_char('\0', tables); + p = skipsp(p); + if (*p++ != '=') + { + parse_error("missing = in variable definition", ""); + return; + } + add_cmd_char(EV_OK|A_EXTRA, tables); } - - add_cmd_char(EV_OK|A_EXTRA, tables); - p = skipsp(p); while (*p != '\0') { @@ -510,24 +584,22 @@ parse_varline(line, tables) /* * Parse a line from the lesskey file. */ - static void -parse_line(line, tables) - char *line; - struct lesskey_tables *tables; +static void parse_line(char *line, struct lesskey_tables *tables) { char *p; /* * See if it is a control line. */ - if (control_line(line, tables)) + p = control_line(line, tables); + if (p == NULL) return; /* * Skip leading white space. * Replace the final newline with a null byte. * Ignore blank lines and comments. */ - p = clean_line(line); + p = clean_line(p); if (*p == '\0') return; @@ -540,10 +612,7 @@ parse_line(line, tables) /* * Parse a lesskey source file and store result in tables. */ - int -parse_lesskey(infile, tables) - char *infile; - struct lesskey_tables *tables; +int parse_lesskey(char *infile, struct lesskey_tables *tables) { FILE *desc; char line[1024]; @@ -555,6 +624,8 @@ parse_lesskey(infile, tables) init_tables(tables); errors = 0; linenum = 0; + if (less_version == 0) + less_version = lstrtoi(version, NULL, 10); /* * Open the input file. @@ -563,7 +634,7 @@ parse_lesskey(infile, tables) desc = stdin; else if ((desc = fopen(infile, "r")) == NULL) { - /* parse_error("cannot open lesskey file ", infile); */ + /* parse_error("cannot open lesskey file %s", infile); */ return (-1); } @@ -575,6 +646,6 @@ parse_lesskey(infile, tables) ++linenum; parse_line(line, tables); } - + fclose(desc); return (errors); } |