示例#1
0
/*
this function displays the current
history entry
*/
void _el_display_history()
{
  int line_len;
  int h_len;
  
  
  _el_set_cursor(-rl_point);
  if ((!(_el_hs.entries)) || (!_el_mb2w
    (_el_hs.entries[_el_hs.offset]->line, &_el_wide))) {
    return;
  }
  h_len = (int)wcslen(_el_wide);
  line_len = (int)wcslen(_el_line_buffer);
  if (h_len > (_EL_BUF_LEN - 1)) {
    h_len = _EL_BUF_LEN - 1;
    _el_wide[_EL_BUF_LEN - 1] = '\0';
  }
  wcscpy_s(_el_line_buffer, _el_line_buffer_size, _el_wide);
  wcscpy_s(_el_print, _el_line_buffer_size, _el_wide);
  wcscpy_s(_el_line_buffer, _el_line_buffer_size, _el_wide);
  rl_point = (int)h_len;
  if (h_len < line_len) {
    _el_add_char(_el_print, _T(' '), line_len - h_len);
  }
  _el_print_string(_el_print);
  _el_set_cursor(h_len);
}
示例#2
0
/*
insert character(s) on the command line
*/
int _el_insert_char(wchar_t *buf, int n)
{
  int c;
  int eff_n;
  int line_len;
  
  
  line_len = (int)wcslen(_el_line_buffer);
  /*
  get line length from the current
  logical cursor position
  to the end, including the terminal '\0'
  */
  c = (int)wcslen(&(_el_line_buffer[rl_point])) + 1;
  eff_n = n;
  /*
  if the buffer is not large enough, cut down
  the number of inserted chars
  */
  if ((line_len + n) >= _EL_BUF_LEN) {
    eff_n = _EL_BUF_LEN - line_len - 1;
  }
  /*
  make the insertion
  */
  memmove(&_el_line_buffer[rl_point + eff_n],
    &_el_line_buffer[rl_point], c * sizeof(wchar_t));
  memcpy(&_el_line_buffer[rl_point], buf, eff_n * sizeof(wchar_t));
  /*
  copy the inserted chars into the string
  for subsequent printing
  */
  memcpy(_el_print, &_el_line_buffer[rl_point],
    (c + eff_n) * sizeof(wchar_t));
  _el_print[c + eff_n] = _T('\0');
  /*
  set the new logical cursor position
  */
  rl_point += eff_n;
  /*
  print the insertion
  */
  if (_el_print_string(_el_print)) {
    return -1;
  }
  /*
  set the new cursor position
  */
  if (_el_set_cursor(eff_n)) {
    return -1;
  }
  if (!_el_w2mb(_el_line_buffer, &rl_line_buffer)) {
    return -1;
  }
  
  return 0;
}
示例#3
0
/*
main readline function
*/
char *readline(const char *prompt)
{
  wchar_t buf[_EL_CONSOLE_BUF_LEN];
  char **array = NULL;
  char *ret_string = NULL;
  int start = 0;
  int end = 0;
  int compl_pos = -1;
  int n = 0;
  int index = 0;
  int len = 0;
  int line_len = 0;
  int old_width = 0;
  int width = 0;
  UINT32 ctrl = 0;
  UINT32 special = 0;
  COORD coord;
  DWORD count = 0;
  INPUT_RECORD irBuffer;
  CONSOLE_SCREEN_BUFFER_INFO sbInfo;
  static int piped_input_finished = FALSE;

  if (piped_input_finished) {
	  return NULL;
  }
  
  _el_ctrl_c_pressed = FALSE;
  _el_line_buffer = NULL;
  _el_temp_print = NULL;
  _el_next_compl = NULL;
  rl_line_buffer = NULL;
  _el_file_name = NULL;
  _el_dir_name = NULL;
  _el_old_arg = NULL;
  _el_wide = NULL;
  _el_text = NULL;
  _el_text_mb = NULL;
  _el_compl_array = NULL;
  _el_completer_word_break_characters = NULL;
  rl_point = 0;
  rl_attempted_completion_over = 0;
  _el_compl_index = 0;
  _el_n_compl = 0;
  _el_h_in = NULL;
  _el_h_out = NULL;
  wcscpy_s(_el_basic_file_break_characters,
    _EL_MAX_FILE_BREAK_CHARACTERS, _EL_BASIC_FILE_BREAK_CHARACTERS);
  memset(&coord, 0, sizeof(COORD));
  memset(buf, 0, _EL_CONSOLE_BUF_LEN * sizeof(wchar_t));
  memset(&irBuffer, 0, sizeof(INPUT_RECORD));
  /*
  allocate buffers
  */
  _el_line_buffer_size = _EL_BUF_LEN + 1;
  _el_line_buffer = (wchar_t *)malloc(_el_line_buffer_size * sizeof(wchar_t));
  if (!_el_mb2w((char *)rl_basic_word_break_characters,
    &_el_basic_word_break_characters)) {
    _el_clean_exit();
    return NULL;
  }
  if (rl_completer_word_break_characters) {
    if (!_el_mb2w((char *)rl_completer_word_break_characters,
      &_el_completer_word_break_characters)) {
      _el_clean_exit();
      return NULL;
    }
  }
  if (!(_el_line_buffer)) {
    _el_clean_exit();
    return NULL;
  }
  memset(_el_line_buffer, 0, _el_line_buffer_size * sizeof(wchar_t));
  rl_attempted_completion_over = 0;
  _el_print = (wchar_t *)malloc(_el_line_buffer_size * sizeof(wchar_t));
  if (!(_el_print)) {
    _el_clean_exit();
    return NULL;
  }
  memset(_el_print, 0, _el_line_buffer_size * sizeof(wchar_t));
  rl_prompt = _strdup(prompt);
  if (!(rl_prompt)) {
    _el_clean_exit();
    return NULL;
  }
  if (!_el_mb2w((char *)prompt, &_el_prompt)) {
    _el_clean_exit();
    return NULL;
  }
  _el_prompt_len = (int)wcslen(_el_prompt);
  /*
  get I/O handles for current console
  */
  _el_h_in = GetStdHandle(STD_INPUT_HANDLE);
  _el_h_out = GetStdHandle(STD_OUTPUT_HANDLE);
  if ((!(_el_h_in)) || (!(_el_h_out))) {
    _el_clean_exit();
    return NULL;
  }
  /*
  set console modes
  */
  _el_prev_in_cm_saved = GetConsoleMode(_el_h_in, &_el_prev_in_cm);
  _el_prev_out_cm_saved = GetConsoleMode(_el_h_out, &_el_prev_out_cm);
  SetConsoleMode(_el_h_in, ENABLE_PROCESSED_INPUT
    | ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE
    | ENABLE_QUICK_EDIT_MODE);
  SetConsoleMode(_el_h_out, ENABLE_PROCESSED_OUTPUT);
  SetConsoleCtrlHandler((PHANDLER_ROUTINE)
    _el_signal_handler, TRUE);
  rl_point = 0;
  while ((buf[0] != VK_RETURN)
    && (!_el_ctrl_c_pressed) && _el_line_buffer) {
    /*
    get screen buffer info from the current console
    */
    if (!GetConsoleScreenBufferInfo(_el_h_out, &sbInfo)) {
      _el_clean_exit();
      return NULL;
    }
    _el_temp_print_size = sbInfo.dwSize.X + 1;
    if (!(_el_temp_print = realloc(_el_temp_print,
      _el_temp_print_size * sizeof(wchar_t)))) {
      _el_clean_exit();
      return NULL;
    }
    _el_temp_print[0] = _T('\0');
    /*
    compute the current visible console width
    */
    width = sbInfo.srWindow.Right - sbInfo.srWindow.Left + 1;
    /*
    if the user has changed the window size
    update the view
    */
    if (old_width != width) {
      line_len = (int)wcslen(_el_line_buffer);
      sbInfo.dwCursorPosition.X = 0;
      if (old_width) {
        n = (_el_prompt_len + line_len - 1) / old_width;
        sbInfo.dwCursorPosition.Y -= n;
        coord.Y = sbInfo.dwCursorPosition.Y;
      }
      if (!SetConsoleCursorPosition(_el_h_out,
        sbInfo.dwCursorPosition)) {
        _el_clean_exit();
        return NULL;
      }
      if (_el_print_string(_el_prompt)) {
        _el_clean_exit();
        return NULL;
      }
      if (_el_set_cursor(_el_prompt_len)) {
        _el_clean_exit();
        return NULL;
      }
      if (_el_print_string(_el_line_buffer)) {
        _el_clean_exit();
        return NULL;
      }
      if (_el_set_cursor(line_len)) {
        _el_clean_exit();
        return NULL;
      }
      if (old_width && (old_width < width)) {
        coord.X = 0;
        coord.Y += (_el_prompt_len + line_len - 1) / width + 1;
        FillConsoleOutputCharacter(_el_h_out, _T(' '),
          sbInfo.dwSize.X * (n + 2), coord, &count);
      }
    }
    old_width = width;
    /*
    wait for console events
    */
    if (!PeekConsoleInput(_el_h_in, &irBuffer, 1, &count)) {
		/* Check we're possibly piped from another program. */
		BOOL ret;
		char *pos, buf[8192];
		DWORD to_read = sizeof(buf);

		/* Can't guarantee Unicode here, we don't control the data passed through the pipe. */
		pos = buf;
		memset(pos, 0, sizeof(buf));

		do {
			ret = ReadFile(_el_h_in, pos, to_read, &count, 0);
			pos += count;
			to_read -= count;
		} while (ret && to_read > 0);

		if (pos == buf) {
			_el_clean_exit();
			return NULL;
		} else if (to_read > 0) {
			/* Tried to fill the buf, but there's nothing anymore. Force finish. */
			piped_input_finished = TRUE;
		}

		buf[pos - buf] = '\0';
		ret_string = _strdup(buf);

		_el_clean_exit();

		return ret_string;
    }
    if (count) {
      if ((irBuffer.EventType == KEY_EVENT) && irBuffer.Event.KeyEvent.bKeyDown) {
        /*
        the user pressed a key
        */
        ctrl = (irBuffer.Event.KeyEvent.dwControlKeyState
          & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED));
        if (irBuffer.Event.KeyEvent.uChar.UnicodeChar == _T('\n')) {
          if (!ReadConsoleInput(_el_h_in, &irBuffer, 1, &count)) {
            _el_clean_exit();
            return NULL;
          }
          buf[0] = VK_RETURN;
          continue;
        }
        if (irBuffer.Event.KeyEvent.uChar.UnicodeChar == _T('\0')) {
          /*
          if it is a special key, just remove it from the buffer
          */
          if (!ReadConsoleInput(_el_h_in, &irBuffer, 1, &count)) {
            _el_clean_exit();
            return NULL;
          }
          special = irBuffer.Event.KeyEvent.wVirtualKeyCode;
          /*
          parse the special key
          */
          switch (special) {
            /*
            arrow left, arrow right 
            HOME and END keys
            */
            case VK_LEFT:
            case VK_RIGHT:
            case VK_HOME:
            case VK_END:
            if (_el_move_cursor(special, ctrl)) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            arrow up: display previous history element (if any)
            after recording the current command line
            */
            case VK_UP:
            if (_el_display_prev_hist()) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            page up: display the first history element (if any)
            after recording the current command line
            */
            case VK_PRIOR:
            if (_el_display_first_hist()) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            arrow down: display next history element (if any)
            after recording the current command line
            */
            case VK_DOWN:
            if (_el_display_next_hist()) {
              _el_clean_exit();
              return NULL;
            }
            break;

            case VK_NEXT:
            /*
            page down: display last history element (if any)
            after recording the current command line
            */
            if (_el_display_last_hist()) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            delete char
            */
            case VK_DELETE:
            if (rl_point != wcslen(_el_line_buffer)) {
              if (_el_delete_char(VK_DELETE, 1)) {
                _el_clean_exit();
                return NULL;
              }
              _el_compl_index = 0;
              compl_pos = -1;
            }
            break;
          }
        }
        else {
          /*
          if it is a normal key, remove it from the buffer
          */
          memset(buf, 0, _EL_CONSOLE_BUF_LEN * sizeof(wchar_t));
          if (!ReadConsole(_el_h_in, buf, 1, &count, NULL)) {
            _el_clean_exit();
            return NULL;
          }
          /*
          then parse it
          */
          switch (buf[0]) {
            /*
            backspace
            */
            case VK_BACK:
            if (rl_point) {
              _el_compl_index = 0;
              compl_pos = -1;
              if (_el_delete_char(VK_BACK, 1)) {
                _el_clean_exit();
                return NULL;
              }
            }
            break;

            /*
            TAB: do completion
            */
            case VK_TAB:
            if ((!array) || (rl_point != compl_pos)) {
              _el_free_array(array);
              index = 0;
              if (_el_text) {
                free(_el_text);
                _el_text = NULL;
              }
              if (!(_el_text = _el_get_compl_text(&start, &end))) {
                _el_clean_exit();
                return NULL;
              }
              if (_el_old_arg) {
                _el_old_arg[0] = _T('\0');
              }
              if (!_el_w2mb(_el_text, &_el_text_mb)) {
                _el_clean_exit();
                return NULL;
              }
              if (!_el_w2mb(_el_line_buffer, &rl_line_buffer)) {
                _el_clean_exit();
                return NULL;
              }
              array = (rl_attempted_completion_function
                ? rl_attempted_completion_function(_el_text_mb, start, end)
                : rl_completion_matches(_el_text_mb, (rl_completion_entry_function
                ? rl_completion_entry_function : rl_filename_completion_function)));
              if (!array) {
                _el_clean_exit();
                return NULL;
              }
            }
            if (!array[index]) {
              index = 0;
            }
            if (array[index]) {
              if (!_el_mb2w(array[index], &_el_next_compl)) {
                _el_clean_exit();
                return NULL;
              }
              len = 0;
              if (_el_old_arg) {
                len = (int)wcslen(_el_old_arg);
                #if 0
                fwprintf(stderr, _T("VK_TAB) _el_old_arg = '%s', len = %d\n"), _el_old_arg, len);
                fflush(stderr);
                #endif
              }
              if (!len) {
                len = (int)wcslen(_el_text);
              }
              if (len) {
                if (_el_delete_char(VK_BACK, len)) {
                  _el_clean_exit();
                  return NULL;
                }
              }
              len = (int)wcslen(_el_next_compl);
              if (!(_el_old_arg = realloc(_el_old_arg,
                (len + 1) * sizeof(wchar_t)))) {
                return NULL;
              }
              _el_old_arg[len] = _T('\0');
              memcpy(_el_old_arg, _el_next_compl, len * sizeof(wchar_t));
              line_len = (int)wcslen(_el_line_buffer);
              if (_el_insert_char(_el_next_compl, len)) {
                _el_clean_exit();
                return NULL;
              }
              free(_el_next_compl);
              _el_next_compl = NULL;
              compl_pos = ((rl_point && (!wcschr(_el_completer_word_break_characters
                ? _el_completer_word_break_characters : _el_basic_word_break_characters,
                _el_line_buffer[rl_point - 1]))) ? rl_point : -1);
              ++index;
            }
            break;
            
            /*
            ENTER: move the cursor to end of line,
            then return to the caller program
            */
            case VK_RETURN:
            if (_el_set_cursor((int)wcslen(_el_line_buffer) - rl_point)) {
              _el_clean_exit();
              return NULL;
            }
            break;
            
            /*
            delete word
            */
            case 0x17:  /* CTRL + W */
            if (ctrl) {
              if (!rl_point) {
                break;
              }
              n = 1;
              while (((rl_point - n) > 0)
                && (iswspace(_el_line_buffer[rl_point - n]))) {
                ++n;
              }
              while ((rl_point - n)
                && (!iswspace(_el_line_buffer[rl_point - n]))) {
                ++n;
              }
              if (rl_point - n) {
                --n;
              }
              _el_compl_index = 0;
              compl_pos = -1;
              if (_el_delete_char(VK_BACK, n)) {
                _el_clean_exit();
                return NULL;
              }
              break;
            }
            
            /*
            delete until end of line
            */
            case 0x0B:  /* CTRL + K */
            if (ctrl) {
              line_len = (int)wcslen(_el_line_buffer);
              if (rl_point < line_len) {
                _el_compl_index = 0;
                compl_pos = -1;
                if (_el_delete_char(VK_DELETE, line_len - rl_point)) {
                  _el_clean_exit();
                  return NULL;
                }
              }
              break;
            }

            /*
            beginning-of-line
            */
            case 0x01:  /* CTRL + A */
            if (_el_move_cursor(VK_HOME, 0)) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            end-of-line
            */
            case 0x05:  /* CTRL + E */
            if (_el_move_cursor(VK_END, 0)) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            forward-char
            */
            case 0x06:  /* CTRL + F */
            if (_el_move_cursor(VK_RIGHT, 0)) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            backward-char
            */
            case 0x02:  /* CTRL + B */
            if (_el_move_cursor(VK_LEFT, 0)) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            previous-line
            */
            case 0x10:  /* CTRL + P */
            if (_el_display_prev_hist()) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            next-line
            */
            case 0x0E:  /* CTRL + N */
            if (_el_display_next_hist()) {
              _el_clean_exit();
              return NULL;
            }
            break;

            /*
            delete char
            */
            case 0x04:  /* CTRL + D */
            if (rl_point != wcslen(_el_line_buffer)) {
              if (_el_delete_char(VK_DELETE, 1)) {
                _el_clean_exit();
                return NULL;
              }
              _el_compl_index = 0;
              compl_pos = -1;
            }
            break;
            
            /*
            if it is a printable character, print it
            NOTE: I have later commented out the
            iswprint() check since for instance it
            prevents the euro sign from being printed
            */
            default:
            /*if (iswprint(buf[0])) {*/
              _el_compl_index = 0;
              compl_pos = -1;
              if (_el_insert_char(buf, 1)) {
                _el_clean_exit();
                return NULL;
              }
            /*}*/
          }
        }
      }
      /*
      if it was not a keyboard event, just remove it from buffer
      */
      else if (!ReadConsoleInput(_el_h_in, &irBuffer, 1, &count)) {
        _el_clean_exit();
        return NULL;
      }
    }
    else {
      /*
      wait for console input
      */
      WaitForSingleObject(_el_h_in, INFINITE);
    }
  }
  
  printf("\n");
  history_set_pos(history_length());
  /*
  if CTRL+C has been pressed, return an empty string
  */
  if (_el_line_buffer) {
    if (_el_ctrl_c_pressed) {
      n = (int)wcslen(_el_line_buffer) - rl_point;
      if (n) {
        _el_set_cursor(n);
      }
      _el_line_buffer[0] = _T('\0');
    }
    _el_w2mb(_el_line_buffer, &rl_line_buffer);
    ret_string = _strdup(rl_line_buffer);
  }
  _el_clean_exit();
  
  return ret_string;
}
示例#4
0
/*
move the cursor
*/
int _el_move_cursor(UINT32 vk, UINT32 ctrl)
{
  int len;
  int offset = 0;
  int first = 0;
  
  
  len = (int)wcslen(_el_line_buffer);
  switch (vk) {
    case VK_LEFT:
    /*
    if the user wants to go left
    and we are already at the beginning
    of the line, then do nothing
    */
    if (!rl_point) {
      return 0;
    }
    /*
    if the user wants to move left
    characterwise, go back one character
    with both the physical and the logical
    cursors
    */
    if (!ctrl) {
      offset = -1;
      --rl_point;
    }
    else {
      /*
      if the user wants to move left
      wordwise, first move left to the first
      alphanumeric character, checking if
      beginning of line has been reached
      */
      while (rl_point && (!iswalnum
        (_el_line_buffer[rl_point]))) {
        --rl_point;
        --offset;
      }
      /*
      move to the beginning of the word
      */
      first = 0;
      while (rl_point && (iswalnum
        (_el_line_buffer[rl_point - 1]) || (!first))) {
        ++first;
        --rl_point;
        --offset;
      }
    }
    break;
    
    case VK_RIGHT:
    /*
    if the user wants to go right
    and we are already at the end
    of the line, then do nothing
    */
    if (rl_point == len) {
      return 0;
    }
    /*
    if the user wants to move right
    characterwise, go ahead one character
    with both the physical and the logical
    cursors
    */
    if (!ctrl) {
      offset = 1;
      ++rl_point;
    }
    else {
      /*
      if the user wants to move right
      wordwise, first move right to the first
      alphanumeric character, checking if
      end of line has been reached
      */
      while ((rl_point < len) && (!iswalnum
        (_el_line_buffer[rl_point]))) {
        ++rl_point;
          ++offset;
      }
      /*
      move to the end of the word
      */
      first = 0;
      while ((rl_point < len) && (iswalnum
        (_el_line_buffer[rl_point]) || (!first))) {
        ++first;
        ++rl_point;
          ++offset;
      }
    }
    break;
    
    case VK_HOME:
    /*
    move to the beginning of line
    */
    offset = (rl_point ? -rl_point : 0);
    rl_point = 0;
    break;
    
    case VK_END:
    /*
    move to the end of line
    */
    offset = len - rl_point;
    rl_point = len;
    break;
    
    default:
    return -1;
  }

  /*
  set the physical cursor position
  */
  return (offset ? _el_set_cursor(offset) : 0);
}
示例#5
0
/*
delete character(s) on the command line
*/
int _el_delete_char(UINT32 vk, int n)
{
  int c;
  int line_len;
  int eff_n;
  
  
  line_len = (int)wcslen(_el_line_buffer);
  eff_n = n;
  switch (vk) {
    case VK_DELETE:
    /*
    the character in correspondence
    of the cursor is to be deleted;
    check that we are not going to delete
    more characters than those which exist
    between the logical cursor position
    and the end of line
    */
    if ((line_len - rl_point) < n) {
      eff_n = line_len - rl_point;
    }

    break;
    
    case VK_BACK:
    /*
    the character before
    the cursor is to be deleted
    check that we are not going to delete
    more characters than those which exist
    between the logical cursor position
    and the beginning of line
    */
    if ((rl_point - n) >= 0) {
      rl_point -= n;
    }
    else {
      eff_n = rl_point;
      rl_point = 0;
    }
    /*
    with backspace we need to reposition
    the cursor as well
    */
    if (_el_set_cursor(-eff_n)) {
      return -1;
    }
    break;
    
    default:
    return -1;
  }
  c = (int)wcslen(&_el_line_buffer[rl_point]) + 1;
  /*
  cut out deleted characters
  */
  memmove(&_el_line_buffer[rl_point],
    &_el_line_buffer[rl_point + eff_n],
    (c - eff_n) * sizeof(wchar_t));
  /*
  copy the characters from the current cursor
  position to end of line in a string
  */
  memcpy(_el_print, &_el_line_buffer[rl_point],
    (c - eff_n) * sizeof(wchar_t));
  _el_print[c - eff_n] = '\0';
  /*
  add spaces to the string to be printed
  to clear out "tails" from the command line
  */
  _el_add_char(_el_print, _T(' '), n);
  if (!_el_w2mb(_el_line_buffer, &rl_line_buffer)) {
    return -1;
  }
  
  /*
  print out and goodbye
  */
  return _el_print_string(_el_print);
}