View of xos/usr/lib/readline/input.c


XOS | Parent Directory | View | Download

/* Copyright (C) 2008  Emmanuel Varoquaux
 
   This file is part of XOS.
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
#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,            /* ESC [ sequences */
  ST_ESC2                                   /* ESC O sequences */
};
 
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) /* C-q, C-v */
      return make_cmd_char(CM_INSERT_CHAR, c);
    if (tty_isig) { /* emulation des signaux du terminal */
      if (c == tty_intr)
        return make_cmd(CM_INTERRUPT);
      if (c == tty_quit || c == tty_susp)
        /* laisse l'etat inchange */
        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': /* ^H */
          return make_cmd(CM_BW_DELETE_CHAR);
        case '\t': /* ^I */
          return make_cmd_char(CM_INSERT_CHAR, '\t');
        case '\n': /* ^J */
          return make_cmd(CM_ACCEPT_LINE);
        case '\v': /* ^K */
          return make_cmd(CM_KILL_LINE);
        case '\f': /* ^L */
          return make_cmd(CM_CLEAR_SCREEN);
        case '\r': /* ^M */
          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: /* ESC (Meta) */
      if (isascii(c) && isupper(c))
        c = tolower(c);
      switch (c) {
      case ctrl('G'):
        goto abort;
      case '\b': /* ^H */
        return make_cmd(CM_BW_KILL_WORD);
      case '\t': /* ^I */
        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: /* C-x */
      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: /* "\e[" (escape sequence) */
      switch (c) {
      case 'A': /* UpArrow (ANSI) */
        return make_cmd(CM_PREV_HIST);
      case 'B': /* DownArrow (ANSI) */
        return make_cmd(CM_NEXT_HIST);
      case 'C': /* RightArrow (ANSI) */
        return make_cmd(CM_MOVE_FW_CHAR);
      case 'D': /* LeftArrow (ANSI) */
        return make_cmd(CM_MOVE_BW_CHAR);
      case 'F': /* End (ANSI) */
        return make_cmd(CM_MOVE_END);
      case 'H': /* Home (ANSI) */
        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: /* "\e[[" */
      break;
    case ST_ESC1_2: /* "\e[{num} */
      if (isascii(c) && isdigit(c)) {
        n = n * 10 + (c - '0');
        state = ST_ESC1_2;
        continue;
      }
      if (c == '~') {
        switch (n) {
        case 1: /* Home (Linux) */
          return make_cmd(CM_MOVE_START);
        case 2: /* Insert (VT200, Linux) */
          return make_cmd(CM_TOOGLE_OVWRT_MODE);
        case 3: /* Delete (VT200, Linux) */
          return make_cmd(CM_DELETE_CHAR);
        case 4: /* End (Linux) */
          return make_cmd(CM_MOVE_END);
        case 5: /* PageUp (VT200, Linux) */
          return make_cmd(CM_PREV_HIST);
        case 6: /* PageDown (VT200, Linux) */
          return make_cmd(CM_NEXT_HIST);
        }
        break;
      }
      break;
    case ST_ESC2: /* "\eO" (escape sequence) */
      switch (c) {
      case 'A': /* UpArrow (keypad) */
        return make_cmd(CM_PREV_HIST);
      case 'B': /* DownArrow (keypad) */
        return make_cmd(CM_NEXT_HIST);
      case 'C': /* RightArrow (keypad) */
        return make_cmd(CM_MOVE_FW_CHAR);
      case 'D': /* LeftArrow (keypad) */
        return make_cmd(CM_MOVE_BW_CHAR);
      case 'F': /* End (keypad) */
        return make_cmd(CM_MOVE_END);
      case 'H': /* Home (keypad) */
        return make_cmd(CM_MOVE_START);
      }
      break;
    }
  abort:
    ding();
    state = ST_STANDARD;
  }
}