#include "input.h"
#include "output.h"
#include "tty.h"
#include "terminal.h"
#include "line.h"
#include "misc.h"
#include <readline/rlvars.h>
#include <string.h>
#include <unistd.h>
enum {
ST_STANDARD, ST_QUOTED, ST_META, ST_CTLX,
ST_ESC1, ST_ESC1_1, ST_ESC1_2,
ST_ESC2
};
static int read_char()
{
unsigned char c;
if (read(fileno(rl_instream), &c, 1) != 1)
return EOF;
return c;
}
int read_cmd()
{
int state;
int n;
int c;
state = ST_STANDARD;
n = 0;
while (1) {
if ((c = read_char()) == EOF) {
if (line_end == 0)
return make_cmd(CM_EOF);
return make_cmd(CM_ACCEPT_LINE);
}
if (state == ST_QUOTED)
return make_cmd_char(CM_INSERT_CHAR, c);
if (tty_isig) {
if (c == tty_intr)
return make_cmd(CM_INTERRUPT);
if (c == tty_quit || c == tty_susp)
continue;
}
switch (state) {
case ST_STANDARD:
if (isascii(c) && iscntrl(c)) {
switch (c) {
case ctrl('@'):
return make_cmd(CM_SET_MARK);
case ctrl('A'):
return make_cmd(CM_MOVE_START);
case ctrl('B'):
return make_cmd(CM_MOVE_BW_CHAR);
case ctrl('D'):
if (line_end == 0)
return make_cmd(CM_EOF);
return make_cmd(CM_DELETE_CHAR);
case ctrl('E'):
return make_cmd(CM_MOVE_END);
case ctrl('F'):
return make_cmd(CM_MOVE_FW_CHAR);
case ctrl('G'):
goto abort;
case '\b':
return make_cmd(CM_BW_DELETE_CHAR);
case '\t':
return make_cmd_char(CM_INSERT_CHAR, '\t');
case '\n':
return make_cmd(CM_ACCEPT_LINE);
case '\v':
return make_cmd(CM_KILL_LINE);
case '\f':
return make_cmd(CM_CLEAR_SCREEN);
case '\r':
return make_cmd(CM_ACCEPT_LINE);
case ctrl('N'):
return make_cmd(CM_NEXT_HIST);
case ctrl('P'):
return make_cmd(CM_PREV_HIST);
case ctrl('Q'):
state = ST_QUOTED;
continue;
case ctrl('U'):
return make_cmd(CM_BW_KILL_LINE);
case ctrl('V'):
state = ST_QUOTED;
continue;
case ctrl('W'):
return make_cmd(CM_BW_KILL_WORD_WSP);
case ctrl('X'):
state = ST_CTLX;
continue;
case ctrl('Y'):
return make_cmd(CM_YANK);
case '\e':
state = ST_META;
continue;
case RUBOUT:
return make_cmd(CM_BW_DELETE_CHAR);
}
break;
}
return make_cmd_char(CM_INSERT_CHAR, c);
case ST_META:
if (isascii(c) && isupper(c))
c = tolower(c);
switch (c) {
case ctrl('G'):
goto abort;
case '\b':
return make_cmd(CM_BW_KILL_WORD);
case '\t':
return make_cmd_char(CM_INSERT_CHAR, '\t');
case ctrl('R'):
return make_cmd(CM_REVERT_LINE);
case ' ':
return make_cmd(CM_SET_MARK);
case '<':
return make_cmd(CM_BEGIN_HIST);
case '>':
return make_cmd(CM_END_HIST);
case 'O':
state = ST_ESC2;
continue;
case 'b':
return make_cmd(CM_MOVE_BW_WORD);
case 'd':
return make_cmd(CM_KILL_WORD);
case 'f':
return make_cmd(CM_MOVE_FW_WORD);
case 'r':
return make_cmd(CM_REVERT_LINE);
case 'y':
return make_cmd(CM_YANK_POP);
case '[':
state = ST_ESC1;
continue;
case RUBOUT:
return make_cmd(CM_BW_KILL_WORD);
}
break;
case ST_CTLX:
if (isascii(c) && isupper(c))
c = tolower(c);
switch (c) {
case ctrl('G'):
goto abort;
case ctrl('X'):
return make_cmd(CM_EXCHANGE_POINT_AND_MARK);
case 'r':
return make_cmd(CM_REFRESH_LINE);
case RUBOUT:
return make_cmd(CM_BW_KILL_LINE);
}
break;
case ST_ESC1:
switch (c) {
case 'A':
return make_cmd(CM_PREV_HIST);
case 'B':
return make_cmd(CM_NEXT_HIST);
case 'C':
return make_cmd(CM_MOVE_FW_CHAR);
case 'D':
return make_cmd(CM_MOVE_BW_CHAR);
case 'F':
return make_cmd(CM_MOVE_END);
case 'H':
return make_cmd(CM_MOVE_START);
case '[':
state = ST_ESC1_1;
continue;
}
if (isascii(c) && isdigit(c)) {
n = c - '0';
state = ST_ESC1_2;
continue;
}
break;
case ST_ESC1_1:
break;
case ST_ESC1_2:
if (isascii(c) && isdigit(c)) {
n = n * 10 + (c - '0');
state = ST_ESC1_2;
continue;
}
if (c == '~') {
switch (n) {
case 1:
return make_cmd(CM_MOVE_START);
case 2:
return make_cmd(CM_TOOGLE_OVWRT_MODE);
case 3:
return make_cmd(CM_DELETE_CHAR);
case 4:
return make_cmd(CM_MOVE_END);
case 5:
return make_cmd(CM_PREV_HIST);
case 6:
return make_cmd(CM_NEXT_HIST);
}
break;
}
break;
case ST_ESC2:
switch (c) {
case 'A':
return make_cmd(CM_PREV_HIST);
case 'B':
return make_cmd(CM_NEXT_HIST);
case 'C':
return make_cmd(CM_MOVE_FW_CHAR);
case 'D':
return make_cmd(CM_MOVE_BW_CHAR);
case 'F':
return make_cmd(CM_MOVE_END);
case 'H':
return make_cmd(CM_MOVE_START);
}
break;
}
abort:
ding();
state = ST_STANDARD;
}
}