version 1.7, 2014/04/25 13:38:21 |
version 1.8, 2015/11/05 22:08:44 |
|
|
* |
* |
* For more information, see the README file. |
* For more information, see the README file. |
*/ |
*/ |
|
/* |
|
* Modified for use with illumos. |
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
|
*/ |
|
|
|
|
/* |
/* |
* Routines to decode user commands. |
* Routines to decode user commands. |
* |
* |
|
|
#include "lesskey.h" |
#include "lesskey.h" |
|
|
extern int erase_char, erase2_char, kill_char; |
extern int erase_char, erase2_char, kill_char; |
extern int secure; |
extern int secure, less_is_more; |
|
|
#define SK(k) \ |
#define SK(k) \ |
SK_SPECIAL_KEY, (k), 6, 1, 1, 1 |
SK_SPECIAL_KEY, (k), 6, 1, 1, 1 |
/* |
/* |
* Command table is ordered roughly according to expected |
* Command table is ordered roughly according to expected |
|
|
|
|
static unsigned char cmdtable[] = |
static unsigned char cmdtable[] = |
{ |
{ |
'\r',0, A_F_LINE, |
'\r', 0, A_F_LINE, |
'\n',0, A_F_LINE, |
'\n', 0, A_F_LINE, |
'e',0, A_F_LINE, |
'e', 0, A_F_LINE, |
'j',0, A_F_LINE, |
'j', 0, A_F_LINE, |
SK(SK_DOWN_ARROW),0, A_F_LINE, |
SK(SK_DOWN_ARROW), 0, A_F_LINE, |
CONTROL('E'),0, A_F_LINE, |
CONTROL('E'), 0, A_F_LINE, |
CONTROL('N'),0, A_F_LINE, |
CONTROL('N'), 0, A_F_LINE, |
'k',0, A_B_LINE, |
'k', 0, A_B_LINE, |
'y',0, A_B_LINE, |
'y', 0, A_B_LINE, |
CONTROL('Y'),0, A_B_LINE, |
CONTROL('Y'), 0, A_B_LINE, |
SK(SK_CONTROL_K),0, A_B_LINE, |
SK(SK_CONTROL_K), 0, A_B_LINE, |
CONTROL('P'),0, A_B_LINE, |
CONTROL('P'), 0, A_B_LINE, |
SK(SK_UP_ARROW),0, A_B_LINE, |
SK(SK_UP_ARROW), 0, A_B_LINE, |
'J',0, A_FF_LINE, |
'J', 0, A_FF_LINE, |
'K',0, A_BF_LINE, |
'K', 0, A_BF_LINE, |
'Y',0, A_BF_LINE, |
'Y', 0, A_BF_LINE, |
'd',0, A_F_SCROLL, |
'd', 0, A_F_SCROLL, |
CONTROL('D'),0, A_F_SCROLL, |
CONTROL('D'), 0, A_F_SCROLL, |
'u',0, A_B_SCROLL, |
'u', 0, A_B_SCROLL, |
CONTROL('U'),0, A_B_SCROLL, |
CONTROL('U'), 0, A_B_SCROLL, |
' ',0, A_F_SCREEN, |
' ', 0, A_F_SCREEN, |
'f',0, A_F_SCREEN, |
'f', 0, A_F_SCREEN, |
CONTROL('F'),0, A_F_SCREEN, |
CONTROL('F'), 0, A_F_SCREEN, |
CONTROL('V'),0, A_F_SCREEN, |
CONTROL('V'), 0, A_F_SCREEN, |
SK(SK_PAGE_DOWN),0, A_F_SCREEN, |
SK(SK_PAGE_DOWN), 0, A_F_SCREEN, |
'b',0, A_B_SCREEN, |
'b', 0, A_B_SCREEN, |
CONTROL('B'),0, A_B_SCREEN, |
CONTROL('B'), 0, A_B_SCREEN, |
ESC,'v',0, A_B_SCREEN, |
ESC, 'v', 0, A_B_SCREEN, |
SK(SK_PAGE_UP),0, A_B_SCREEN, |
SK(SK_PAGE_UP), 0, A_B_SCREEN, |
'z',0, A_F_WINDOW, |
'z', 0, A_F_WINDOW, |
'w',0, A_B_WINDOW, |
'w', 0, A_B_WINDOW, |
ESC,' ',0, A_FF_SCREEN, |
ESC, ' ', 0, A_FF_SCREEN, |
'F',0, A_F_FOREVER, |
'F', 0, A_F_FOREVER, |
ESC,'F',0, A_F_UNTIL_HILITE, |
ESC, 'F', 0, A_F_UNTIL_HILITE, |
'R',0, A_FREPAINT, |
'R', 0, A_FREPAINT, |
'r',0, A_REPAINT, |
'r', 0, A_REPAINT, |
CONTROL('R'),0, A_REPAINT, |
CONTROL('R'), 0, A_REPAINT, |
CONTROL('L'),0, A_REPAINT, |
CONTROL('L'), 0, A_REPAINT, |
ESC,'u',0, A_UNDO_SEARCH, |
ESC, 'u', 0, A_UNDO_SEARCH, |
'g',0, A_GOLINE, |
'g', 0, A_GOLINE, |
SK(SK_HOME),0, A_GOLINE, |
SK(SK_HOME), 0, A_GOLINE, |
'<',0, A_GOLINE, |
'<', 0, A_GOLINE, |
ESC,'<',0, A_GOLINE, |
ESC, '<', 0, A_GOLINE, |
'p',0, A_PERCENT, |
'p', 0, A_PERCENT, |
'%',0, A_PERCENT, |
'%', 0, A_PERCENT, |
ESC,'[',0, A_LSHIFT, |
ESC, '[', 0, A_LSHIFT, |
ESC,']',0, A_RSHIFT, |
ESC, ']', 0, A_RSHIFT, |
ESC,'(',0, A_LSHIFT, |
ESC, '(', 0, A_LSHIFT, |
ESC,')',0, A_RSHIFT, |
ESC, ')', 0, A_RSHIFT, |
SK(SK_RIGHT_ARROW),0, A_RSHIFT, |
SK(SK_RIGHT_ARROW), 0, A_RSHIFT, |
SK(SK_LEFT_ARROW),0, A_LSHIFT, |
SK(SK_LEFT_ARROW), 0, A_LSHIFT, |
'{',0, A_F_BRACKET|A_EXTRA, '{','}',0, |
'{', 0, A_F_BRACKET|A_EXTRA, '{', '}', 0, |
'}',0, A_B_BRACKET|A_EXTRA, '{','}',0, |
'}', 0, A_B_BRACKET|A_EXTRA, '{', '}', 0, |
'(',0, A_F_BRACKET|A_EXTRA, '(',')',0, |
'(', 0, A_F_BRACKET|A_EXTRA, '(', ')', 0, |
')',0, A_B_BRACKET|A_EXTRA, '(',')',0, |
')', 0, A_B_BRACKET|A_EXTRA, '(', ')', 0, |
'[',0, A_F_BRACKET|A_EXTRA, '[',']',0, |
'[', 0, A_F_BRACKET|A_EXTRA, '[', ']', 0, |
']',0, A_B_BRACKET|A_EXTRA, '[',']',0, |
']', 0, A_B_BRACKET|A_EXTRA, '[', ']', 0, |
ESC,CONTROL('F'),0, A_F_BRACKET, |
ESC, CONTROL('F'), 0, A_F_BRACKET, |
ESC,CONTROL('B'),0, A_B_BRACKET, |
ESC, CONTROL('B'), 0, A_B_BRACKET, |
'G',0, A_GOEND, |
'G', 0, A_GOEND, |
ESC,'>',0, A_GOEND, |
ESC, '>', 0, A_GOEND, |
'>',0, A_GOEND, |
'>', 0, A_GOEND, |
SK(SK_END),0, A_GOEND, |
SK(SK_END), 0, A_GOEND, |
'P',0, A_GOPOS, |
'P', 0, A_GOPOS, |
|
|
'0',0, A_DIGIT, |
'0', 0, A_DIGIT, |
'1',0, A_DIGIT, |
'1', 0, A_DIGIT, |
'2',0, A_DIGIT, |
'2', 0, A_DIGIT, |
'3',0, A_DIGIT, |
'3', 0, A_DIGIT, |
'4',0, A_DIGIT, |
'4', 0, A_DIGIT, |
'5',0, A_DIGIT, |
'5', 0, A_DIGIT, |
'6',0, A_DIGIT, |
'6', 0, A_DIGIT, |
'7',0, A_DIGIT, |
'7', 0, A_DIGIT, |
'8',0, A_DIGIT, |
'8', 0, A_DIGIT, |
'9',0, A_DIGIT, |
'9', 0, A_DIGIT, |
'.',0, A_DIGIT, |
'.', 0, A_DIGIT, |
|
|
'=',0, A_STAT, |
'=', 0, A_STAT, |
CONTROL('G'),0, A_STAT, |
CONTROL('G'), 0, A_STAT, |
':','f',0, A_STAT, |
':', 'f', 0, A_STAT, |
'/',0, A_F_SEARCH, |
'/', 0, A_F_SEARCH, |
'?',0, A_B_SEARCH, |
'?', 0, A_B_SEARCH, |
ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0, |
ESC, '/', 0, A_F_SEARCH|A_EXTRA, '*', 0, |
ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0, |
ESC, '?', 0, A_B_SEARCH|A_EXTRA, '*', 0, |
'n',0, A_AGAIN_SEARCH, |
'n', 0, A_AGAIN_SEARCH, |
ESC,'n',0, A_T_AGAIN_SEARCH, |
ESC, 'n', 0, A_T_AGAIN_SEARCH, |
'N',0, A_REVERSE_SEARCH, |
'N', 0, A_REVERSE_SEARCH, |
ESC,'N',0, A_T_REVERSE_SEARCH, |
ESC, 'N', 0, A_T_REVERSE_SEARCH, |
'&',0, A_FILTER, |
'&', 0, A_FILTER, |
'm',0, A_SETMARK, |
'm', 0, A_SETMARK, |
'\'',0, A_GOMARK, |
'\'', 0, A_GOMARK, |
CONTROL('X'),CONTROL('X'),0, A_GOMARK, |
CONTROL('X'), CONTROL('X'), 0, A_GOMARK, |
'E',0, A_EXAMINE, |
'E', 0, A_EXAMINE, |
':','e',0, A_EXAMINE, |
':', 'e', 0, A_EXAMINE, |
CONTROL('X'),CONTROL('V'),0, A_EXAMINE, |
CONTROL('X'), CONTROL('V'), 0, A_EXAMINE, |
':','n',0, A_NEXT_FILE, |
':', 'n', 0, A_NEXT_FILE, |
':','p',0, A_PREV_FILE, |
':', 'p', 0, A_PREV_FILE, |
't',0, A_NEXT_TAG, |
't', 0, A_NEXT_TAG, |
'T',0, A_PREV_TAG, |
'T', 0, A_PREV_TAG, |
':','x',0, A_INDEX_FILE, |
':', 'x', 0, A_INDEX_FILE, |
':','d',0, A_REMOVE_FILE, |
':', 'd', 0, A_REMOVE_FILE, |
'-',0, A_OPT_TOGGLE, |
':', 't', 0, A_OPT_TOGGLE|A_EXTRA, 't', 0, |
':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0, |
'|', 0, A_PIPE, |
's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0, |
'v', 0, A_VISUAL, |
'_',0, A_DISP_OPTION, |
'!', 0, A_SHELL, |
'|',0, A_PIPE, |
'+', 0, A_FIRSTCMD, |
'v',0, A_VISUAL, |
|
'!',0, A_SHELL, |
|
'+',0, A_FIRSTCMD, |
|
|
|
'H',0, A_HELP, |
'H', 0, A_HELP, |
'h',0, A_HELP, |
'h', 0, A_HELP, |
SK(SK_F1),0, A_HELP, |
SK(SK_F1), 0, A_HELP, |
'V',0, A_VERSION, |
'V', 0, A_VERSION, |
'q',0, A_QUIT, |
'q', 0, A_QUIT, |
'Q',0, A_QUIT, |
'Q', 0, A_QUIT, |
':','q',0, A_QUIT, |
':', 'q', 0, A_QUIT, |
':','Q',0, A_QUIT, |
':', 'Q', 0, A_QUIT, |
'Z','Z',0, A_QUIT |
'Z', 'Z', 0, A_QUIT |
}; |
}; |
|
|
|
static unsigned char lesstable[] = { |
|
'-', 0, A_OPT_TOGGLE, |
|
's', 0, A_OPT_TOGGLE|A_EXTRA, 'o', 0, |
|
'_', 0, A_DISP_OPTION |
|
}; |
|
|
|
static unsigned char moretable[] = { |
|
's', 0, A_F_SKIP |
|
}; |
|
|
static unsigned char edittable[] = |
static unsigned char edittable[] = |
{ |
{ |
'\t',0, EC_F_COMPLETE, /* TAB */ |
'\t', 0, EC_F_COMPLETE, /* TAB */ |
'\17',0, EC_B_COMPLETE, /* BACKTAB */ |
'\17', 0, EC_B_COMPLETE, /* BACKTAB */ |
SK(SK_BACKTAB),0, EC_B_COMPLETE, /* BACKTAB */ |
SK(SK_BACKTAB), 0, EC_B_COMPLETE, /* BACKTAB */ |
ESC,'\t',0, EC_B_COMPLETE, /* ESC TAB */ |
ESC, '\t', 0, EC_B_COMPLETE, /* ESC TAB */ |
CONTROL('L'),0, EC_EXPAND, /* CTRL-L */ |
CONTROL('L'), 0, EC_EXPAND, /* CTRL-L */ |
CONTROL('V'),0, EC_LITERAL, /* BACKSLASH */ |
CONTROL('V'), 0, EC_LITERAL, /* BACKSLASH */ |
CONTROL('A'),0, EC_LITERAL, /* BACKSLASH */ |
CONTROL('A'), 0, EC_LITERAL, /* BACKSLASH */ |
ESC,'l',0, EC_RIGHT, /* ESC l */ |
ESC, 'l', 0, EC_RIGHT, /* ESC l */ |
SK(SK_RIGHT_ARROW),0, EC_RIGHT, /* RIGHTARROW */ |
SK(SK_RIGHT_ARROW), 0, EC_RIGHT, /* RIGHTARROW */ |
ESC,'h',0, EC_LEFT, /* ESC h */ |
ESC, 'h', 0, EC_LEFT, /* ESC h */ |
SK(SK_LEFT_ARROW),0, EC_LEFT, /* LEFTARROW */ |
SK(SK_LEFT_ARROW), 0, EC_LEFT, /* LEFTARROW */ |
ESC,'b',0, EC_W_LEFT, /* ESC b */ |
ESC, 'b', 0, EC_W_LEFT, /* ESC b */ |
ESC,SK(SK_LEFT_ARROW),0, EC_W_LEFT, /* ESC LEFTARROW */ |
ESC, SK(SK_LEFT_ARROW), 0, EC_W_LEFT, /* ESC LEFTARROW */ |
SK(SK_CTL_LEFT_ARROW),0, EC_W_LEFT, /* CTRL-LEFTARROW */ |
SK(SK_CTL_LEFT_ARROW), 0, EC_W_LEFT, /* CTRL-LEFTARROW */ |
ESC,'w',0, EC_W_RIGHT, /* ESC w */ |
ESC, 'w', 0, EC_W_RIGHT, /* ESC w */ |
ESC,SK(SK_RIGHT_ARROW),0, EC_W_RIGHT, /* ESC RIGHTARROW */ |
ESC, SK(SK_RIGHT_ARROW), 0, EC_W_RIGHT, /* ESC RIGHTARROW */ |
SK(SK_CTL_RIGHT_ARROW),0, EC_W_RIGHT, /* CTRL-RIGHTARROW */ |
SK(SK_CTL_RIGHT_ARROW), 0, EC_W_RIGHT, /* CTRL-RIGHTARROW */ |
ESC,'i',0, EC_INSERT, /* ESC i */ |
ESC, 'i', 0, EC_INSERT, /* ESC i */ |
SK(SK_INSERT),0, EC_INSERT, /* INSERT */ |
SK(SK_INSERT), 0, EC_INSERT, /* INSERT */ |
ESC,'x',0, EC_DELETE, /* ESC x */ |
ESC, 'x', 0, EC_DELETE, /* ESC x */ |
SK(SK_DELETE),0, EC_DELETE, /* DELETE */ |
SK(SK_DELETE), 0, EC_DELETE, /* DELETE */ |
ESC,'X',0, EC_W_DELETE, /* ESC X */ |
ESC, 'X', 0, EC_W_DELETE, /* ESC X */ |
ESC,SK(SK_DELETE),0, EC_W_DELETE, /* ESC DELETE */ |
ESC, SK(SK_DELETE), 0, EC_W_DELETE, /* ESC DELETE */ |
SK(SK_CTL_DELETE),0, EC_W_DELETE, /* CTRL-DELETE */ |
SK(SK_CTL_DELETE), 0, EC_W_DELETE, /* CTRL-DELETE */ |
SK(SK_CTL_BACKSPACE),0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */ |
SK(SK_CTL_BACKSPACE), 0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */ |
ESC,'\b',0, EC_W_BACKSPACE, /* ESC BACKSPACE */ |
ESC, '\b', 0, EC_W_BACKSPACE, /* ESC BACKSPACE */ |
ESC,'0',0, EC_HOME, /* ESC 0 */ |
ESC, '0', 0, EC_HOME, /* ESC 0 */ |
SK(SK_HOME),0, EC_HOME, /* HOME */ |
SK(SK_HOME), 0, EC_HOME, /* HOME */ |
ESC,'$',0, EC_END, /* ESC $ */ |
ESC, '$', 0, EC_END, /* ESC $ */ |
SK(SK_END),0, EC_END, /* END */ |
SK(SK_END), 0, EC_END, /* END */ |
ESC,'k',0, EC_UP, /* ESC k */ |
ESC, 'k', 0, EC_UP, /* ESC k */ |
SK(SK_UP_ARROW),0, EC_UP, /* UPARROW */ |
SK(SK_UP_ARROW), 0, EC_UP, /* UPARROW */ |
ESC,'j',0, EC_DOWN, /* ESC j */ |
ESC, 'j', 0, EC_DOWN, /* ESC j */ |
SK(SK_DOWN_ARROW),0, EC_DOWN, /* DOWNARROW */ |
SK(SK_DOWN_ARROW), 0, EC_DOWN, /* DOWNARROW */ |
CONTROL('G'),0, EC_ABORT, /* CTRL-G */ |
CONTROL('G'), 0, EC_ABORT, /* CTRL-G */ |
}; |
}; |
|
|
/* |
/* |
|
|
/* |
/* |
* Expand special key abbreviations in a command table. |
* Expand special key abbreviations in a command table. |
*/ |
*/ |
static void |
static void |
expand_special_keys(table, len) |
expand_special_keys(char *table, int len) |
char *table; |
|
int len; |
|
{ |
{ |
register char *fm; |
char *fm; |
register char *to; |
char *to; |
register int a; |
int a; |
char *repl; |
char *repl; |
int klen; |
int klen; |
|
|
for (fm = table; fm < table + len; ) |
for (fm = table; fm < table + len; ) { |
{ |
|
/* |
/* |
* Rewrite each command in the table with any |
* Rewrite each command in the table with any |
* special key abbreviations expanded. |
* special key abbreviations expanded. |
*/ |
*/ |
for (to = fm; *fm != '\0'; ) |
for (to = fm; *fm != '\0'; ) { |
{ |
if (*fm != SK_SPECIAL_KEY) { |
if (*fm != SK_SPECIAL_KEY) |
|
{ |
|
*to++ = *fm++; |
*to++ = *fm++; |
continue; |
continue; |
} |
} |
|
|
repl = special_key_str(fm[1]); |
repl = special_key_str(fm[1]); |
klen = fm[2] & 0377; |
klen = fm[2] & 0377; |
fm += klen; |
fm += klen; |
if (repl == NULL || (int) strlen(repl) > klen) |
if (repl == NULL || strlen(repl) > klen) |
repl = "\377"; |
repl = "\377"; |
while (*repl != '\0') |
while (*repl != '\0') |
*to++ = *repl++; |
*to++ = *repl++; |
} |
} |
*to++ = '\0'; |
*to++ = '\0'; |
/* |
/* |
* Fill any unused bytes between end of command and |
* Fill any unused bytes between end of command and |
* the action byte with A_SKIP. |
* the action byte with A_SKIP. |
*/ |
*/ |
while (to <= fm) |
while (to <= fm) |
*to++ = A_SKIP; |
*to++ = A_SKIP; |
fm++; |
fm++; |
a = *fm++ & 0377; |
a = *fm++ & 0377; |
if (a & A_EXTRA) |
if (a & A_EXTRA) { |
{ |
|
while (*fm++ != '\0') |
while (*fm++ != '\0') |
continue; |
continue; |
} |
} |
|
|
/* |
/* |
* Initialize the command lists. |
* Initialize the command lists. |
*/ |
*/ |
public void |
void |
init_cmds() |
init_cmds(void) |
{ |
{ |
/* |
/* |
* Add the default command tables. |
* Add the default command tables. |
*/ |
*/ |
add_fcmd_table((char*)cmdtable, sizeof(cmdtable)); |
add_fcmd_table((char *)cmdtable, sizeof (cmdtable)); |
add_ecmd_table((char*)edittable, sizeof(edittable)); |
add_ecmd_table((char *)edittable, sizeof (edittable)); |
#if USERFILE |
if (less_is_more) { |
|
add_fcmd_table((char *)moretable, sizeof (moretable)); |
|
return; |
|
} else { |
|
add_fcmd_table((char *)lesstable, sizeof (lesstable)); |
|
} |
|
|
/* |
/* |
* For backwards compatibility, |
|
* try to add tables in the OLD system lesskey file. |
|
*/ |
|
#ifdef BINDIR |
|
add_hometable(NULL, BINDIR "/.sysless", 1); |
|
#endif |
|
/* |
|
* Try to add the tables in the system lesskey file. |
* Try to add the tables in the system lesskey file. |
*/ |
*/ |
add_hometable("LESSKEY_SYSTEM", LESSKEYFILE_SYS, 1); |
add_hometable("LESSKEY_SYSTEM", LESSKEYFILE_SYS, 1); |
|
|
* Try to add the tables in the standard lesskey file "$HOME/.less". |
* Try to add the tables in the standard lesskey file "$HOME/.less". |
*/ |
*/ |
add_hometable("LESSKEY", LESSKEYFILE, 0); |
add_hometable("LESSKEY", LESSKEYFILE, 0); |
#endif |
|
} |
} |
|
|
/* |
/* |
* Add a command table. |
* Add a command table. |
*/ |
*/ |
static int |
static int |
add_cmd_table(tlist, buf, len) |
add_cmd_table(struct tablelist **tlist, char *buf, int len) |
struct tablelist **tlist; |
|
char *buf; |
|
int len; |
|
{ |
{ |
register struct tablelist *t; |
struct tablelist *t; |
|
|
if (len == 0) |
if (len == 0) |
return (0); |
return (0); |
/* |
/* |
* Allocate a tablelist structure, initialize it, |
* Allocate a tablelist structure, initialize it, |
* and link it into the list of tables. |
* and link it into the list of tables. |
*/ |
*/ |
if ((t = (struct tablelist *) |
if ((t = calloc(1, sizeof (struct tablelist))) == NULL) { |
calloc(1, sizeof(struct tablelist))) == NULL) |
|
{ |
|
return (-1); |
return (-1); |
} |
} |
expand_special_keys(buf, len); |
expand_special_keys(buf, len); |
|
|
/* |
/* |
* Add a command table. |
* Add a command table. |
*/ |
*/ |
public void |
void |
add_fcmd_table(buf, len) |
add_fcmd_table(char *buf, int len) |
char *buf; |
|
int len; |
|
{ |
{ |
if (add_cmd_table(&list_fcmd_tables, buf, len) < 0) |
if (add_cmd_table(&list_fcmd_tables, buf, len) < 0) |
error("Warning: some commands disabled", NULL_PARG); |
error("Warning: some commands disabled", NULL_PARG); |
|
|
/* |
/* |
* Add an editing command table. |
* Add an editing command table. |
*/ |
*/ |
public void |
void |
add_ecmd_table(buf, len) |
add_ecmd_table(char *buf, int len) |
char *buf; |
|
int len; |
|
{ |
{ |
if (add_cmd_table(&list_ecmd_tables, buf, len) < 0) |
if (add_cmd_table(&list_ecmd_tables, buf, len) < 0) |
error("Warning: some edit commands disabled", NULL_PARG); |
error("Warning: some edit commands disabled", NULL_PARG); |
|
|
/* |
/* |
* Add an environment variable table. |
* Add an environment variable table. |
*/ |
*/ |
static void |
static void |
add_var_table(tlist, buf, len) |
add_var_table(struct tablelist **tlist, char *buf, int len) |
struct tablelist **tlist; |
|
char *buf; |
|
int len; |
|
{ |
{ |
if (add_cmd_table(tlist, buf, len) < 0) |
if (add_cmd_table(tlist, buf, len) < 0) |
error("Warning: environment variables from lesskey file unavailable", NULL_PARG); |
error("Warning: environment variables from " |
|
"lesskey file unavailable", NULL_PARG); |
} |
} |
|
|
/* |
/* |
* Search a single command table for the command string in cmd. |
* Search a single command table for the command string in cmd. |
*/ |
*/ |
static int |
static int |
cmd_search(cmd, table, endtable, sp) |
cmd_search(const char *cmd, char *table, char *endtable, char **sp) |
char *cmd; |
|
char *table; |
|
char *endtable; |
|
char **sp; |
|
{ |
{ |
register char *p; |
char *p; |
register char *q; |
const char *q; |
register int a; |
int a; |
|
|
*sp = NULL; |
*sp = NULL; |
for (p = table, q = cmd; p < endtable; p++, q++) |
for (p = table, q = cmd; p < endtable; p++, q++) { |
{ |
if (*p == *q) { |
if (*p == *q) |
|
{ |
|
/* |
/* |
* Current characters match. |
* Current characters match. |
* If we're at the end of the string, we've found it. |
* If we're at the end of the string, we've found it. |
|
|
* after the null at the end of the string |
* after the null at the end of the string |
* in the command table. |
* in the command table. |
*/ |
*/ |
if (*p == '\0') |
if (*p == '\0') { |
{ |
|
a = *++p & 0377; |
a = *++p & 0377; |
while (a == A_SKIP) |
while (a == A_SKIP) |
a = *++p & 0377; |
a = *++p & 0377; |
if (a == A_END_LIST) |
if (a == A_END_LIST) { |
{ |
|
/* |
/* |
* We get here only if the original |
* We get here only if the original |
* cmd string passed in was empty (""). |
* cmd string passed in was empty (""). |
|
|
/* |
/* |
* Check for an "extra" string. |
* Check for an "extra" string. |
*/ |
*/ |
if (a & A_EXTRA) |
if (a & A_EXTRA) { |
{ |
|
*sp = ++p; |
*sp = ++p; |
a &= ~A_EXTRA; |
a &= ~A_EXTRA; |
} |
} |
return (a); |
return (a); |
} |
} |
} else if (*q == '\0') |
} else if (*q == '\0') { |
{ |
|
/* |
/* |
* Hit the end of the user's command, |
* Hit the end of the user's command, |
* but not the end of the string in the command table. |
* but not the end of the string in the command table. |
* The user's command is incomplete. |
* The user's command is incomplete. |
*/ |
*/ |
return (A_PREFIX); |
return (A_PREFIX); |
} else |
} else { |
{ |
|
/* |
/* |
* Not a match. |
* Not a match. |
* Skip ahead to the next command in the |
* Skip ahead to the next command in the |
* command table, and reset the pointer |
* command table, and reset the pointer |
* to the beginning of the user's command. |
* to the beginning of the user's command. |
*/ |
*/ |
if (*p == '\0' && p[1] == A_END_LIST) |
if (*p == '\0' && p[1] == A_END_LIST) { |
{ |
|
/* |
/* |
* A_END_LIST is a special marker that tells |
* A_END_LIST is a special marker that tells |
* us to abort the cmd search. |
* us to abort the cmd search. |
*/ |
*/ |
return (A_UINVALID); |
return (A_UINVALID); |
|
|
* Decode a command character and return the associated action. |
* Decode a command character and return the associated action. |
* The "extra" string, if any, is returned in sp. |
* The "extra" string, if any, is returned in sp. |
*/ |
*/ |
static int |
static int |
cmd_decode(tlist, cmd, sp) |
cmd_decode(struct tablelist *tlist, const char *cmd, char **sp) |
struct tablelist *tlist; |
|
char *cmd; |
|
char **sp; |
|
{ |
{ |
register struct tablelist *t; |
struct tablelist *t; |
register int action = A_INVALID; |
int action = A_INVALID; |
|
|
/* |
/* |
* Search thru all the command tables. |
* Search thru all the command tables. |
* Stop when we find an action which is not A_INVALID. |
* Stop when we find an action which is not A_INVALID. |
*/ |
*/ |
for (t = tlist; t != NULL; t = t->t_next) |
for (t = tlist; t != NULL; t = t->t_next) { |
{ |
|
action = cmd_search(cmd, t->t_start, t->t_end, sp); |
action = cmd_search(cmd, t->t_start, t->t_end, sp); |
if (action != A_INVALID) |
if (action != A_INVALID) |
break; |
break; |
|
|
/* |
/* |
* Decode a command from the cmdtables list. |
* Decode a command from the cmdtables list. |
*/ |
*/ |
public int |
int |
fcmd_decode(cmd, sp) |
fcmd_decode(const char *cmd, char **sp) |
char *cmd; |
|
char **sp; |
|
{ |
{ |
return (cmd_decode(list_fcmd_tables, cmd, sp)); |
return (cmd_decode(list_fcmd_tables, cmd, sp)); |
} |
} |
|
|
/* |
/* |
* Decode a command from the edittables list. |
* Decode a command from the edittables list. |
*/ |
*/ |
public int |
int |
ecmd_decode(cmd, sp) |
ecmd_decode(const char *cmd, char **sp) |
char *cmd; |
|
char **sp; |
|
{ |
{ |
return (cmd_decode(list_ecmd_tables, cmd, sp)); |
return (cmd_decode(list_ecmd_tables, cmd, sp)); |
} |
} |
|
|
* Get the value of an environment variable. |
* Get the value of an environment variable. |
* Looks first in the lesskey file, then in the real environment. |
* Looks first in the lesskey file, then in the real environment. |
*/ |
*/ |
public char * |
char * |
lgetenv(var) |
lgetenv(char *var) |
char *var; |
|
{ |
{ |
int a; |
int a; |
char *s; |
char *s; |
|
|
|
/* |
|
* Ignore lookups of any LESS* setting when we are more, and ignore |
|
* the less key files |
|
*/ |
|
if (less_is_more) { |
|
if (strncmp(var, "LESS", 4) == 0) { |
|
return (NULL); |
|
} |
|
return (getenv(var)); |
|
} |
a = cmd_decode(list_var_tables, var, &s); |
a = cmd_decode(list_var_tables, var, &s); |
if (a == EV_OK) |
if (a == EV_OK) |
return (s); |
return (s); |
|
|
return (NULL); |
return (NULL); |
} |
} |
|
|
#if USERFILE |
|
/* |
/* |
* Get an "integer" from a lesskey file. |
* Get an "integer" from a lesskey file. |
* Integers are stored in a funny format: |
* Integers are stored in a funny format: |
* two bytes, low order first, in radix KRADIX. |
* two bytes, low order first, in radix KRADIX. |
*/ |
*/ |
static int |
static int |
gint(sp) |
gint(char **sp) |
char **sp; |
|
{ |
{ |
int n; |
int n; |
|
|
|
|
/* |
/* |
* Process an old (pre-v241) lesskey file. |
* Process an old (pre-v241) lesskey file. |
*/ |
*/ |
static int |
static int |
old_lesskey(buf, len) |
old_lesskey(char *buf, int len) |
char *buf; |
|
int len; |
|
{ |
{ |
/* |
/* |
* Old-style lesskey file. |
* Old-style lesskey file. |
* The file must end with either |
* The file must end with either |
* ...,cmd,0,action |
* ..,cmd,0,action |
* or ...,cmd,0,action|A_EXTRA,string,0 |
* or ...,cmd,0,action|A_EXTRA,string,0 |
* So the last byte or the second to last byte must be zero. |
* So the last byte or the second to last byte must be zero. |
*/ |
*/ |
if (buf[len-1] != '\0' && buf[len-2] != '\0') |
if (buf[len-1] != '\0' && buf[len-2] != '\0') |
|
|
return (0); |
return (0); |
} |
} |
|
|
/* |
/* |
* Process a new (post-v241) lesskey file. |
* Process a new (post-v241) lesskey file. |
*/ |
*/ |
static int |
static int |
new_lesskey(buf, len, sysvar) |
new_lesskey(char *buf, int len, int sysvar) |
char *buf; |
|
int len; |
|
int sysvar; |
|
{ |
{ |
char *p; |
char *p; |
register int c; |
int c; |
register int n; |
int n; |
|
|
/* |
/* |
* New-style lesskey file. |
* New-style lesskey file. |
|
|
buf[len-1] != C2_END_LESSKEY_MAGIC) |
buf[len-1] != C2_END_LESSKEY_MAGIC) |
return (-1); |
return (-1); |
p = buf + 4; |
p = buf + 4; |
for (;;) |
for (;;) { |
{ |
|
c = *p++; |
c = *p++; |
switch (c) |
switch (c) { |
{ |
|
case CMD_SECTION: |
case CMD_SECTION: |
n = gint(&p); |
n = gint(&p); |
add_fcmd_table(p, n); |
add_fcmd_table(p, n); |
|
|
break; |
break; |
case VAR_SECTION: |
case VAR_SECTION: |
n = gint(&p); |
n = gint(&p); |
add_var_table((sysvar) ? |
add_var_table((sysvar) ? |
&list_sysvar_tables : &list_var_tables, p, n); |
&list_sysvar_tables : &list_var_tables, p, n); |
p += n; |
p += n; |
break; |
break; |
case END_SECTION: |
case END_SECTION: |
|
|
/* |
/* |
* Set up a user command table, based on a "lesskey" file. |
* Set up a user command table, based on a "lesskey" file. |
*/ |
*/ |
public int |
int |
lesskey(filename, sysvar) |
lesskey(char *filename, int sysvar) |
char *filename; |
|
int sysvar; |
|
{ |
{ |
register char *buf; |
char *buf; |
register POSITION len; |
off_t len; |
register long n; |
long n; |
register int f; |
int f; |
|
|
if (secure) |
if (secure) |
return (1); |
return (1); |
|
|
* rely on the lesskey program to generate a good .less file. }} |
* rely on the lesskey program to generate a good .less file. }} |
*/ |
*/ |
len = filesize(f); |
len = filesize(f); |
if (len == NULL_POSITION || len < 3) |
if (len == -1 || len < 3) { |
{ |
|
/* |
/* |
* Bad file (valid file must have at least 3 chars). |
* Bad file (valid file must have at least 3 chars). |
*/ |
*/ |
close(f); |
(void) close(f); |
return (-1); |
return (-1); |
} |
} |
if ((buf = (char *) calloc((int)len, sizeof(char))) == NULL) |
if ((buf = calloc((int)len, sizeof (char))) == NULL) { |
{ |
(void) close(f); |
close(f); |
|
return (-1); |
return (-1); |
} |
} |
if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK) |
if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK) { |
{ |
|
free(buf); |
free(buf); |
close(f); |
(void) close(f); |
return (-1); |
return (-1); |
} |
} |
n = read(f, buf, (unsigned int) len); |
n = read(f, buf, (unsigned int) len); |
close(f); |
close(f); |
if (n != len) |
if (n != len) { |
{ |
|
free(buf); |
free(buf); |
return (-1); |
return (-1); |
} |
} |
|
|
/* |
/* |
* Add the standard lesskey file "$HOME/.less" |
* Add the standard lesskey file "$HOME/.less" |
*/ |
*/ |
public void |
void |
add_hometable(envname, def_filename, sysvar) |
add_hometable(char *envname, char *def_filename, int sysvar) |
char *envname; |
|
char *def_filename; |
|
int sysvar; |
|
{ |
{ |
char *filename; |
char *filename; |
PARG parg; |
PARG parg; |
|
|
filename = homefile(def_filename); |
filename = homefile(def_filename); |
if (filename == NULL) |
if (filename == NULL) |
return; |
return; |
if (lesskey(filename, sysvar) < 0) |
if (lesskey(filename, sysvar) < 0) { |
{ |
|
parg.p_string = filename; |
parg.p_string = filename; |
error("Cannot use lesskey file \"%s\"", &parg); |
error("Cannot use lesskey file \"%s\"", &parg); |
} |
} |
free(filename); |
free(filename); |
} |
} |
#endif |
|
|
|
/* |
/* |
* See if a char is a special line-editing command. |
* See if a char is a special line-editing command. |
*/ |
*/ |
public int |
int |
editchar(c, flags) |
editchar(int c, int flags) |
int c; |
|
int flags; |
|
{ |
{ |
int action; |
int action; |
int nch; |
int nch; |
char *s; |
char *s; |
char usercmd[MAX_CMDLEN+1]; |
char usercmd[MAX_CMDLEN+1]; |
|
|
/* |
/* |
* An editing character could actually be a sequence of characters; |
* An editing character could actually be a sequence of characters; |
* for example, an escape sequence sent by pressing the uparrow key. |
* for example, an escape sequence sent by pressing the uparrow key. |
|
|
return (EC_BACKSPACE); |
return (EC_BACKSPACE); |
if (c == kill_char) |
if (c == kill_char) |
return (EC_LINEKILL); |
return (EC_LINEKILL); |
|
|
/* |
/* |
* Collect characters in a buffer. |
* Collect characters in a buffer. |
* Start with the one we have, and get more if we need them. |
* Start with the one we have, and get more if we need them. |
*/ |
*/ |
nch = 0; |
nch = 0; |
do { |
do { |
if (nch > 0) |
if (nch > 0) |
c = getcc(); |
c = getcc(); |
usercmd[nch] = c; |
usercmd[nch] = (char)c; |
usercmd[nch+1] = '\0'; |
usercmd[nch+1] = '\0'; |
nch++; |
nch++; |
action = ecmd_decode(usercmd, &s); |
action = ecmd_decode(usercmd, &s); |
} while (action == A_PREFIX); |
} while (action == A_PREFIX); |
|
|
if (flags & EC_NORIGHTLEFT) |
if (flags & EC_NORIGHTLEFT) { |
{ |
switch (action) { |
switch (action) |
|
{ |
|
case EC_RIGHT: |
case EC_RIGHT: |
case EC_LEFT: |
case EC_LEFT: |
action = A_INVALID; |
action = A_INVALID; |
break; |
break; |
} |
} |
} |
} |
#if CMD_HISTORY |
if (flags & EC_NOHISTORY) { |
if (flags & EC_NOHISTORY) |
|
{ |
|
/* |
/* |
* The caller says there is no history list. |
* The caller says there is no history list. |
* Reject any history-manipulation action. |
* Reject any history-manipulation action. |
*/ |
*/ |
switch (action) |
switch (action) { |
{ |
|
case EC_UP: |
case EC_UP: |
case EC_DOWN: |
case EC_DOWN: |
action = A_INVALID; |
action = A_INVALID; |
break; |
break; |
} |
} |
} |
} |
#endif |
if (flags & EC_NOCOMPLETE) { |
#if TAB_COMPLETE_FILENAME |
|
if (flags & EC_NOCOMPLETE) |
|
{ |
|
/* |
/* |
* The caller says we don't want any filename completion cmds. |
* The caller says we don't want any filename completion cmds. |
* Reject them. |
* Reject them. |
*/ |
*/ |
switch (action) |
switch (action) { |
{ |
|
case EC_F_COMPLETE: |
case EC_F_COMPLETE: |
case EC_B_COMPLETE: |
case EC_B_COMPLETE: |
case EC_EXPAND: |
case EC_EXPAND: |
|
|
break; |
break; |
} |
} |
} |
} |
#endif |
if ((flags & EC_PEEK) || action == A_INVALID) { |
if ((flags & EC_PEEK) || action == A_INVALID) |
|
{ |
|
/* |
/* |
* We're just peeking, or we didn't understand the command. |
* We're just peeking, or we didn't understand the command. |
* Unget all the characters we read in the loop above. |
* Unget all the characters we read in the loop above. |
* This does NOT include the original character that was |
* This does NOT include the original character that was |
* passed in as a parameter. |
* passed in as a parameter. |
*/ |
*/ |
while (nch > 1) |
while (nch > 1) { |
{ |
|
ungetcc(usercmd[--nch]); |
ungetcc(usercmd[--nch]); |
} |
} |
} else |
} else { |
{ |
|
if (s != NULL) |
if (s != NULL) |
ungetsc(s); |
ungetsc(s); |
} |
} |
return action; |
return (action); |
} |
} |
|
|