View of xos/usr/lib/readline/readline.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 <readline/readline.h>
 
#include "localhist.h"
#include "kill.h"
#include "edit.h"
#include "input.h"
#include "output.h"
#include "tty.h"
#include "terminal.h"
#include "line.h"
#include "misc.h"
#include "xmalloc.h"
 
#include <string.h>
 
static int command_is_kill;
static int command_is_yank;
static int last_command_was_kill;
static int last_command_was_yank;
 
static int start_of_current_word()
{
  int newpoint;
 
  newpoint = point;
  while (newpoint != 0 && !letter_or_digit(line[newpoint - 1]))
    newpoint--;
  while (newpoint != 0 && letter_or_digit(line[newpoint - 1]))
    newpoint--;
  return newpoint;
}
 
static int end_of_current_word()
{
  int newpoint;
 
  newpoint = point;
  while (newpoint != line_end && !letter_or_digit(line[newpoint]))
    newpoint++;
  while (newpoint != line_end && letter_or_digit(line[newpoint]))
    newpoint++;
  return newpoint;
}
 
static int previous_whitespace()
{
  int newpoint;
 
  newpoint = point;
  while (newpoint != 0 && whitespace(line[newpoint - 1]))
    newpoint--;
  while (newpoint != 0 && !whitespace(line[newpoint - 1]))
    newpoint--;
  return newpoint;
}
 
static void copy_to_kill_ring(const char *start, const char *end, int append)
{
  int len, oldlen, newlen;
  char *text, *newtext;
 
  len = end - start;
  if (append != 0) {
    text = kill_ring_get();
    oldlen = strlen(text);
    newlen = oldlen + len;
    newtext = xmalloc(newlen + 1);
    if (append > 0) {
      memcpy(newtext, text, oldlen);
      memcpy(newtext + oldlen, start, len);
    }
    else {
      memcpy(newtext, start, len);
      memcpy(newtext + len, text, oldlen);
    }
    newtext[newlen] = '\0';
    kill_ring_replace(newtext);
  }
  else {
    text = xmalloc(len + 1);
    memcpy(text, start, len);
    text[len] = '\0';
    kill_ring_add(text);
  }
}
 
static void kill_region(int start, int end)
{
  if (start != end) {
    copy_to_kill_ring(line + start, line + end, last_command_was_kill ? (mark == start ? 1 : -1) : 0);
    command_is_kill = 1;
  }
  delete_region(start, end);
  set_mark(start);
}
 
static void yank(int start, int end, const char *text)
{
  command_is_yank = 1;
  replace_region_with_text(start, end, text);
  set_mark(start);
}
 
char __attribute__ ((weak, visibility ("default"))) *readline(const char *prompt)
{
  int insert_mode;
  int cmd;
  char c;
  struct linebuf_struct *linebuf;
  int newpoint;
  const char *text;
 
  if (!rl_instream)
    rl_instream = stdin;
  if (!rl_outstream)
    rl_outstream = stdout;
 
  get_term_info();
  setup_tty();
  local_history_init();
  insert_mode = 1;
  begin_editing(prompt, local_history_current());
  command_is_kill = 0;
  command_is_yank = 0;
  while (1) {
    last_command_was_kill = command_is_kill;
    last_command_was_yank = command_is_yank;
    command_is_kill = 0;
    command_is_yank = 0;
    cmd = read_cmd();
    switch (cmd_get_name(cmd)) {
      /* Moving */
    case CM_MOVE_START:
      move_to(0);
      continue;
    case CM_MOVE_END:
      move_to(line_end);
      continue;
    case CM_MOVE_FW_CHAR:
      if (point == line_end)
        goto bad_command;
      move_to(point + 1);
      continue;
    case CM_MOVE_BW_CHAR:
      if (point == 0)
        goto bad_command;
      move_to(point - 1);
      continue;
    case CM_MOVE_FW_WORD:
      move_to(end_of_current_word());
      continue;
    case CM_MOVE_BW_WORD:
      move_to(start_of_current_word());
      continue;
    case CM_CLEAR_SCREEN:
      clear_screen();
      continue;
    case CM_REFRESH_LINE:
      refresh_line();
      continue;
 
      /* History */
    case CM_ACCEPT_LINE:
      accept_line();
      goto end;
    case CM_PREV_HIST:
      if (!(linebuf = local_history_previous()))
        goto bad_command;
      reset_line(linebuf);
      continue;
    case CM_NEXT_HIST:
      if (!(linebuf = local_history_next()))
        goto bad_command;
      reset_line(linebuf);
      continue;
    case CM_BEGIN_HIST:
      if (!(linebuf = local_history_begin()))
        goto bad_command;
      reset_line(linebuf);
      continue;
    case CM_END_HIST:
      if (!(linebuf = local_history_end()))
        goto bad_command;
      reset_line(linebuf);
      continue;
 
      /* Changing Text */
    case CM_DELETE_CHAR:
      if (point == line_end)
        goto bad_command;
      delete_region(point, point + 1);
      continue;
    case CM_BW_DELETE_CHAR:
      if (point == 0)
        goto bad_command;
      if (insert_mode || point == line_end)
        delete_region(point - 1, point);
      else
        erase_region(point - 1, point);
      continue;
    case CM_INSERT_CHAR:
      c = cmd_get_char(cmd);
      if (insert_mode || point == line_end)
        replace_region_with_char(point, point, c);
      else
        replace_region_with_char(point, point + 1, c);
      continue;
    case CM_TOOGLE_OVWRT_MODE:
      insert_mode = !insert_mode;
      continue;
 
      /* Killing */
    case CM_KILL_LINE:
      kill_region(point, line_end);
      continue;
    case CM_BW_KILL_LINE:
      if (point == 0)
        goto bad_command;
      kill_region(0, point);
      continue;
    case CM_KILL_WORD:
      kill_region(point, end_of_current_word());
      continue;
    case CM_BW_KILL_WORD:
      kill_region(start_of_current_word(), point);
      continue;
    case CM_BW_KILL_WORD_WSP:
      if ((newpoint = previous_whitespace()) == point)
        goto bad_command;
      kill_region(newpoint, point);
      continue;
    case CM_YANK:
      if (!(text = kill_ring_get()))
        goto bad_command;
      yank(point, point, text);
      continue;
    case CM_YANK_POP:
      if (!last_command_was_yank)
        goto bad_command;
      text = kill_ring_get();
      yank(point - strlen(text), point, kill_ring_rotate());
      continue;
 
      /* Miscellaneous */
    case CM_REVERT_LINE:
      delete_region(0, line_end);
      continue;
    case CM_SET_MARK:
      set_mark(point);
      continue;
    case CM_EXCHANGE_POINT_AND_MARK:
      if (mark == -1)
        goto bad_command;
      if (mark > line_end) {
        set_mark(-1);
        goto bad_command;
      }
      exchange_point_and_mark();
      continue;
 
      /* divers */
    case CM_INTERRUPT:
      abort_line();
      goto end;
    case CM_EOF:
      discard_line();
      goto end;
    }
  bad_command:
    ding();
  }
 end:
  end_editing();
  local_history_destroy();
  restore_tty();
  return line;
}