示例#1
0
/*
this function may be called after calling
readline() for the last time
if you do, remember to call again
using_history() before calling readline()
*/
void free_history()
{
  int i;
  
  
  if (_el_hs.entries) {
    for (i = 0; i <= _el_hs.size; ++i) {
      if (_el_hs.entries[i]) {
        if (_el_hs.entries[i]->line) {
          free(_el_hs.entries[i]->line);
          _el_hs.entries[i]->line = NULL;
        }
      }
    }
    _el_free_array(_el_hs.entries);
  }
}
示例#2
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;
}
示例#3
0
/*
free memory buffers before exit
*/
void _el_clean_exit()
{
  if (rl_line_buffer) {
    free(rl_line_buffer);
    rl_line_buffer = NULL;
  }
  if (_el_line_buffer) {
    free(_el_line_buffer);
    _el_line_buffer = NULL;
  }
  if (_el_compl_array) {
    _el_free_array(_el_compl_array);
    _el_compl_array = NULL;
  }
  if (_el_print) {
    free(_el_print);
    _el_print = NULL;
  }
  if (_el_temp_print) {
    free(_el_temp_print);
    _el_temp_print = NULL;
  }
  if (_el_next_compl) {
    free(_el_next_compl);
    _el_next_compl = NULL;
  }
  if (_el_completer_word_break_characters) {
    free(_el_completer_word_break_characters);
    _el_completer_word_break_characters = NULL;
  }
  if (_el_basic_word_break_characters) {
    free(_el_basic_word_break_characters);
    _el_basic_word_break_characters = NULL;
  }
  if (rl_prompt) {
    free(rl_prompt);
    rl_prompt = NULL;
  }
  if (_el_old_arg) {
    free(_el_old_arg);
    _el_old_arg = NULL;
  }
  if (_el_wide) {
    free(_el_wide);
    _el_wide = NULL;
  }
  if (_el_text) {
    free(_el_text);
    _el_text = NULL;
  }
  if (_el_text_mb) {
    free(_el_text_mb);
    _el_text_mb = NULL;
  }
  if (_el_file_name) {
    free(_el_file_name);
    _el_file_name = NULL;
  }
  if (_el_dir_name) {
    free(_el_dir_name);
    _el_dir_name = NULL;
  }
  if (_el_prev_in_cm_saved) {
    SetConsoleMode(_el_h_in,
    _el_prev_in_cm | ENABLE_EXTENDED_FLAGS);
  }
  if (_el_prev_out_cm_saved) {
    SetConsoleMode(_el_h_out, _el_prev_out_cm);
  }
  SetConsoleCtrlHandler((PHANDLER_ROUTINE)
    _el_signal_handler, FALSE);
}