Logo Search packages:      
Sourcecode: w3mmee version File versions  Download package

linein.c

#include "fm.h"
#include "local.h"
#include "myctype.h"

#ifdef __EMX__
#include <sys/kbdscan.h>
#endif

#define CLEN (COLS - 2)

static void insertself(char c, InputLineEnv *env),
    insC(InputLineEnv *env), _dcompl(InputLineEnv *env), _rdcompl(InputLineEnv *env);
static void _rcompl(InputLineEnv *env);
#ifdef _EMX_
static int getcntrl();
#endif
#ifdef MANY_CHARSET
static void insMBC(size_t cn, InputLineEnv *env);
#endif

#define iself ((void(*)())insertself)

static void next_compl(int next, InputLineEnv *env);
static Str do_filename_complete(Str ifn, int *status, int next, InputLineEnv *env);
static Str do_hist_complete(Str ifn, int *status, int next, InputLineEnv *env);
static Str do_ci_tab_complete(Str ifn, int *status, int next, InputLineEnv *env);

static KeyTabItem w3mDefaultEditKeyTab[] = {
    K_SET_FUNC(K_GEN(0, K_CTL_ATMARK), FUNCNAME_linein_compl),
    K_SET_FUNC(K_GEN(0, K_CTL_A), FUNCNAME_linein_mvB),
    K_SET_FUNC(K_GEN(0, K_CTL_B), FUNCNAME_linein_mvL),
    K_SET_FUNC(K_GEN(0, K_CTL_C), FUNCNAME_linein_inbrk),
    K_SET_FUNC(K_GEN(0, K_CTL_D), FUNCNAME_linein_delC),
    K_SET_FUNC(K_GEN(0, K_CTL_E), FUNCNAME_linein_mvE),
    K_SET_FUNC(K_GEN(0, K_CTL_F), FUNCNAME_linein_mvR),
    K_SET_FUNC(K_GEN(0, K_CTL_G), FUNCNAME_linein_inbrk),
    K_SET_FUNC(K_GEN(0, K_CTL_H), FUNCNAME_linein_bs),
    K_SET_FUNC(K_GEN(0, K_CTL_J), FUNCNAME_linein_enter),
    K_SET_FUNC(K_GEN(0, K_CTL_K), FUNCNAME_linein_killn),
    K_SET_FUNC(K_GEN(0, K_CTL_M), FUNCNAME_linein_enter),
    K_SET_FUNC(K_GEN(0, K_CTL_N), FUNCNAME_linein_next),
    K_SET_FUNC(K_GEN(0, K_CTL_P), FUNCNAME_linein_prev),
    K_SET_FUNC(K_GEN(0, K_CTL_Q), FUNCNAME_linein_quo),
    K_SET_FUNC(K_GEN(0, K_CTL_R), FUNCNAME_linein_bsw),
    K_SET_FUNC(K_GEN(0, K_CTL_T), FUNCNAME_linein_mvLw),
    K_SET_FUNC(K_GEN(0, K_CTL_U), FUNCNAME_linein_killb),
    K_SET_FUNC(K_GEN(0, K_CTL_V), FUNCNAME_linein_quo),
    K_SET_FUNC(K_GEN(0, K_CTL_X), FUNCNAME_linein_tcompl),
    K_SET_FUNC(K_GEN(0, K_CTL_Y), FUNCNAME_linein_mvRw),
    K_SET_FUNC(K_GEN(0, K_CTL_LBRACKET), FUNCNAME_linein_esc),
    K_SET_FUNC(K_GEN(0, K_ESCB | K_ALPHA_A), FUNCNAME_linein_prev),
    K_SET_FUNC(K_GEN(0, K_ESCB | K_ALPHA_B), FUNCNAME_linein_next),
    K_SET_FUNC(K_GEN(0, K_ESCB | K_ALPHA_C), FUNCNAME_linein_mvR),
    K_SET_FUNC(K_GEN(0, K_ESCB | K_ALPHA_D), FUNCNAME_linein_mvL),
};

KeyTabList w3mDefaultEditKeyTabList = {
    NULL,
    w3mDefaultEditKeyTab,
    sizeof(w3mDefaultEditKeyTab) / sizeof(w3mDefaultEditKeyTab[0]),
    sizeof(w3mDefaultEditKeyTab) / sizeof(w3mDefaultEditKeyTab[0]),
};

static int setStrType(InputLineEnv *env);
static void addPasswd(char *p, Lineprop *pr, int len, int pos, int limit);
static void addStr(char *p, Lineprop *pr, int len, int pos, int limit);

#ifdef JP_CHARSET
static void ins_kanji(Str tmp, InputLineEnv *env);
#endif

static int
same_type_word_char_p(
#ifdef MANY_CHARSET
                  mb_wchar_t x, mb_wchar_t y
#else
                  int x, int y
#endif
                  )
{
    if (!(x & ~0xFF) && IS_ALNUM(x)) {
      if (!(y & ~0xFF) && IS_ALNUM(y))
          return 1;
      else
          return 0;
    }
    else {
      if (!(y & ~0xFF) && IS_ALNUM(y))
          return 0;
      else
          return 1;
    }
}

static int
same_type_path_char_p(
#ifdef MANY_CHARSET
                  mb_wchar_t x, mb_wchar_t y
#else
                  int x, int y
#endif
                  )
{
    if (!(x & ~0xFF) && strchr("/&?", x)) {
      if (!(y & ~0xFF) && strchr("/&?", y))
          return 1;
      else
          return 0;
    }
    else {
      if (!(y & ~0xFF) && strchr("/&?", y))
          return 0;
      else
          return 1;
    }
}

void
call_edit_func(int c, void (*fallback)(char, InputLineEnv *), InputLineEnv *env)
{
    if (env->nstroke < K_LEN_MAX) {
      FuncList *fl;

      ++(env->nstroke);
      env->prev_stroke = K_GEN(env->prev_stroke, c);

      if ((fl = lookupKey(env->prev_stroke, w3mEditKeyTabList))) {
#ifdef MANY_CHARSET
          switch (fl - w3mFuncList) {
          default:
            process_getch_mode(GETCH_MODE_CLR);
            env->i_wchar = FALSE;
          case FUNCNAME_linein_esc:
          case FUNCNAME_linein_nextchar:
            break;
          }
#endif
          fl->func.edit_func(env->prev_stroke, env);
          return;
      }
    }

#ifdef MANY_CHARSET
    if (!env->i_wchar) {
      process_getch_mode(GETCH_MODE_RST);
      env->i_wchar = TRUE;
      return;
    }
    else {
      process_getch_mode(GETCH_MODE_CLR);
      env->i_wchar = FALSE;
    }
#endif

    if (fallback)
      fallback(c, env);
}

void
call_edit_func_nostroke(int c, void (*fallback)(char, InputLineEnv *), InputLineEnv *env)
{
    FuncList *fl;

    env->prev_stroke = K_OVER(env->prev_stroke, c);

    if ((fl = lookupKey(env->prev_stroke, w3mEditKeyTabList))) {
#ifdef MANY_CHARSET
      switch (fl - w3mFuncList) {
      default:
          process_getch_mode(GETCH_MODE_CLR);
          env->i_wchar = FALSE;
      case FUNCNAME_linein_esc:
      case FUNCNAME_linein_nextchar:
          break;
      }
#endif
      fl->func.edit_func(env->prev_stroke, env);
    }
#ifdef MANY_CHARSET
    else if (!env->i_wchar) {
      process_getch_mode(GETCH_MODE_RST);
      env->i_wchar = TRUE;
    }
#endif
    else {
#ifdef MANY_CHARSET
      process_getch_mode(GETCH_MODE_CLR);
      env->i_wchar = FALSE;
#endif

      if (fallback)
          fallback(c, env);
    }
}

int inputLineBusy = 0;
UrgentInputQueue inputLineQueue = {0};

static void
processInputLineQueue(void)
{
    int i = 0;
    char *p;

    do {
      if (*inputLineQueue.v[i].pfp) {
          p = inputLineHist(inputLineQueue.v[i].prompt, inputLineQueue.v[i].def_str,
                        inputLineQueue.v[i].flag, inputLineQueue.v[i].hist);
          fprintf(*inputLineQueue.v[i].pfp, "%s\n", halfdump_buffer_quote(p));
          fflush(*inputLineQueue.v[i].pfp);
      }
    } while (++i < inputLineQueue.n);

    inputLineQueue.n = 0;
}

char *
inputLineHistTabSearch(char *prompt, char *def_str, int flag, Hist *hist, btri_string_tab_t *tab,
                int (*incrfunc)(int ch, Str str, Lineprop *prop))
{
    int opos, x, y, lpos, rpos, epos;
#ifdef MANY_CHARSET
    mb_wchar_t c;
#else
    unsigned char c;
#endif
    char *p;
    Lineprop mode;
#ifdef JP_CHARSET
    Str tmp;
#endif                        /* JP_CHARSET */
    InputLineEnv env;
    int oldbusy, old_y, old_x;

    oldbusy = inputLineBusy;
    inputLineBusy = 1;

    if (w3m_backend) {
      p = backend_inputLine(prompt, def_str, flag, hist);
      goto end;
    }
    else if (!fmInitialized) {
      if (feof(stdin) || ferror(stdin))
          p = def_str ? def_str : "";
      else {
          Str ans;

          if (prompt)
            fputs(prompt, stdout);

          if (def_str && *def_str && !(flag & IN_PASSWORD))
            printf("(default: %s)", def_str);

          if (prompt || (def_str && !(flag & IN_PASSWORD)))
            fflush(stdout);

          ans = Strfgets(stdin);
          Strchop(ans);
          p = ans->length ? ans->ptr : def_str ? def_str : "";
      }

      goto end;
    }

    getyx(old_y, old_x);
    memset(&env, 0, sizeof(env));
    mode = PC_ASCII;
#ifdef JP_CHARSET
    tmp = Strnew();
    env.in_kanji = FALSE;
#endif
    env.is_passwd = FALSE;
    env.same_type_char_p = same_type_word_char_p;

    env.CurrentHist = hist;
    if (hist != NULL) {
      env.use_hist = TRUE;
      env.strCurrentBuf = NULL;
    }
    else
      env.use_hist = FALSE;
    if (flag & (IN_URL | IN_FILENAME)) {
      env.cm_mode = CPL_IMMUTABLE | CPL_ON | (flag & IN_URL ? CPL_URL : 0);
      env.same_type_char_p = same_type_path_char_p;
      env.do_complete = do_filename_complete;
      env.ComplPrivate = New(ComplFileNameEnv);
      ((ComplFileNameEnv *)env.ComplPrivate)->CFileName = ((ComplFileNameEnv *)env.ComplPrivate)->CDirBuf = NULL;
    }
    else if (flag & IN_PASSWORD) {
      env.cm_mode = CPL_IMMUTABLE | CPL_OFF;
      env.is_passwd = TRUE;
    }
    else if (flag & IN_COMMAND) {
      env.cm_mode = CPL_ON | CPL_COMMAND | CPL_WORDS;
      env.do_complete = do_filename_complete;
      env.ComplPrivate = New(ComplFileNameEnv);
      ((ComplFileNameEnv *)env.ComplPrivate)->CFileName = ((ComplFileNameEnv *)env.ComplPrivate)->CDirBuf = NULL;
    }
    else if (tab) {
      env.cm_mode = CPL_IMMUTABLE | CPL_ON | (flag & IN_WORDS ? CPL_WORDS : 0);
      env.do_complete = do_ci_tab_complete;
      env.ComplPrivate = tab;
    }
    else if (hist) {
      env.cm_mode = CPL_ON;
      env.do_complete = do_hist_complete;
    }
    else 
      env.cm_mode = CPL_OFF;
#ifdef MANY_CHARSET
    opos = ttyfix_width(prompt);
#else
    opos = strlen(prompt);
#endif
    epos = CLEN - opos;
    if (epos < 0)
      epos = 0;
    lpos = epos / 3;
    if (lpos > Tabstop) lpos = Tabstop;
    rpos = epos * 2 / 3;
    if (epos - rpos > Tabstop) rpos = epos - Tabstop;
    env.offset = 0;

    if (def_str) {
      env.strBuf = Strnew_charp(def_str);
      env.CLen = env.CPos = setStrType(&env);
    } else {
      env.strBuf = Strnew();
      env.CLen = env.CPos = 0;
    }

    env.i_cont = TRUE;
    env.i_broken = FALSE;
    env.i_quote = FALSE;
    env.cm_next = FALSE;
    env.cm_disp_next = -1;
    env.need_redraw = FALSE;
    do {
      x = calcPosition(env.strBuf->ptr, env.strProp, env.CLen, env.CPos, 0, CP_FORCE);
      if (x - rpos > env.offset) {
          y = calcPosition(env.strBuf->ptr, env.strProp, env.CLen, env.CLen, 0, CP_AUTO);
          if (y - epos > x - rpos)
            env.offset = x - rpos;
          else if (y - epos > 0)
            env.offset = y - epos;
      } else if (x - lpos < env.offset) {
          if (x - lpos > 0)
            env.offset = x - lpos;
          else
            env.offset = 0;
      }
      move(INPUTLINE, 0);
      addstr(prompt);
      if (env.is_passwd)
          addPasswd(env.strBuf->ptr, env.strProp, env.CLen, env.offset, COLS - opos);
      else
          addStr(env.strBuf->ptr, env.strProp, env.CLen, env.offset, COLS - opos);
      clrtoeolx();
      move(INPUTLINE, opos + x - env.offset);
      refresh();
#ifdef USE_IMAGE
      if (activeImage)
          drawImage();
#endif

    next_char:
      env.prev_stroke = env.nstroke = 0;
#ifdef MANY_CHARSET
      if (env.i_wchar)
          switch (c = tty_getwc()) {
          case mb_notchar_enc_invalid:
            env.i_wchar = FALSE;
            process_getch_mode(GETCH_MODE_SKIP);
            break;
          default:
            goto wc_found;
          }
      c = (unsigned char)getch_internal(0);
    wc_found:
#else
      c = getch();
#endif
#ifdef __EMX__
      if (c == 0) {
          if (!(c = getcntrl()))
            goto next_char;
      }
#endif
      env.cm_clear = TRUE;
      env.cm_disp_clear = TRUE;
#ifdef JP_CHARSET
      if (mode == PC_KANJI1) {
          mode = PC_KANJI2;
          if (env.CLen >= STR_LEN)
            goto next_char;
          Strcat_char(tmp, (c | (DisplayCode == CODE_SJIS ? 0 : 0x80)));
          tmp = conv_str(tmp,
                     (DisplayCode == CODE_SJIS ? CODE_SJIS : CODE_EUC), InnerCode);
          ins_kanji(tmp, &env);
          if (incrfunc)
            incrfunc(-1, env.strBuf, env.strProp);
      }
      else
#endif
          if (!env.i_quote &&
            ((CPL_ALWAYS(env.cm_mode) && (c == CTRL_I || c == ' ')) ||
             ((env.cm_mode & CPL_ON) && (c == CTRL_I)))) {
#ifdef EMACS_LIKE_LINEEDIT
            if (emacs_like_lineedit && env.cm_next) {
                _dcompl(&env);
                env.need_redraw = TRUE;
            }
            else
#endif
                {
                  linein_compl(c, &env);
                  env.cm_disp_next = -1;
                }
#ifdef MANY_CHARSET
            process_getch_mode(GETCH_MODE_CLR);
            env.i_wchar = FALSE;
#endif
          }
          else if (!env.i_quote && env.CLen == env.CPos &&
                 env.cm_mode & CPL_ON && c == CTRL_D) {
#ifdef EMACS_LIKE_LINEEDIT
            if (!emacs_like_lineedit) {
#endif
                _dcompl(&env);
                env.need_redraw = TRUE;
#ifdef EMACS_LIKE_LINEEDIT
            }
#endif
#ifdef MANY_CHARSET
            process_getch_mode(GETCH_MODE_CLR);
            env.i_wchar = FALSE;
#endif
          }
          else if (!env.i_quote && c == DEL_CODE) {
            linein_bs(c, &env);
            env.cm_next = FALSE;
            env.cm_disp_next = -1;
#ifdef MANY_CHARSET
            process_getch_mode(GETCH_MODE_CLR);
            env.i_wchar = FALSE;
#endif
          }
          else if (!env.i_quote && c < 0x20) {  /* Control code */
            if (incrfunc == NULL || (c = incrfunc((int)c, env.strBuf, env.strProp)) < 0x20) {
                call_edit_func(c, insertself, &env);
#ifdef MANY_CHARSET
                if (env.i_wchar)
                  goto next_char;
#endif
            }
            if (incrfunc)
                incrfunc(-1, env.strBuf, env.strProp);
            if (env.cm_clear)
                env.cm_next = FALSE;
            if (env.cm_disp_clear)
                env.cm_disp_next = -1;
          }
#ifdef JP_CHARSET
          else if (DisplayCode == CODE_SJIS && 0xa0 <= c && c <= 0xdf) {
            env.i_quote = FALSE;
            env.cm_next = FALSE;
            if (env.CLen >= STR_LEN)
                goto next_char;
            Strclear(tmp);
            Strcat_char(tmp, c);
            tmp = conv_str(tmp, DisplayCode, InnerCode);
            ins_kanji(tmp, &env);
            if (incrfunc)
                incrfunc(-1, env.strBuf, env.strProp);
          }
          else if ((c & 0x80) || env.in_kanji) {      /* Kanji 1 */
            env.i_quote = FALSE;
            env.cm_next = FALSE;
            env.cm_disp_next = -1;
            if (env.CLen >= STR_LEN - 1)
                goto next_char;
            Strclear(tmp);
            Strcat_char(tmp, (c | 0x80));
            mode = PC_KANJI1;
            goto next_char;
          }
#endif                        /* JP_CHARSET */
#ifdef MANY_CHARSET
          else if (!env.i_wchar) {
            process_getch_mode(GETCH_MODE_RST);
            env.i_wchar = TRUE;
            goto next_char;
          }
#endif
          else {
#ifdef MANY_CHARSET
            char tmp[MB_MBC_LEN_MAX];
            size_t cn;
#endif
            env.i_quote = FALSE;
            env.cm_next = FALSE;
            env.cm_disp_next = -1;
#ifdef MANY_CHARSET
            env.i_wchar = FALSE;
            cn = mb_wchar_to_mbc(c, tmp);
            if (STR_LEN - env.CLen < cn)
                goto next_char;
            insMBC(cn, &env);
            bcopy(tmp, &env.strBuf->ptr[env.CPos], cn);
            memset(&env.strProp[env.CPos], (!env.is_passwd && !(c & ~0xFF) && IS_CNTRL(c)) ? PC_CTRL : PC_ASCII, cn);
            env.CPos += cn;
#else
            if (env.CLen >= STR_LEN)
                goto next_char;
            insC(&env);
            env.strBuf->ptr[env.CPos] = c;
            if (!env.is_passwd && IS_CNTRL(c))
                env.strProp[env.CPos] = PC_CTRL;
            else
                env.strProp[env.CPos] = PC_ASCII;
            env.CPos++;
#endif
            mode = PC_ASCII;
            if (incrfunc)
                incrfunc(-1, env.strBuf, env.strProp);
          }
      if (env.CLen && (flag & IN_CHAR))
          break;
    } while (env.i_cont);

    if (env.need_redraw && Currentbuf) {
      next_dcompl_top = -1;
      next_dcompl_env = NULL;
      displayCurrentView(NULL);
    }

    move(INPUTLINE, 0);
    clrtoeol();
    refresh();

    if (env.i_broken) {
      p = NULL;
      goto end;
    }

    p = env.strBuf->ptr;
    if (flag & (IN_FILENAME | IN_COMMAND)) {
      SKIP_BLANKS(p);
    }
    if (env.use_hist && !(flag & IN_URL)) {
      char *q;
      if (!(q = lastHist(hist)) || strcmp(q, p))
          pushHist(hist, p);
    }
end:
    move(old_y, old_x);

    if (!oldbusy && inputLineQueue.n)
      processInputLineQueue();

    inputLineBusy = oldbusy;

    if (!p)
      return p;
    else if (flag & IN_FILENAME)
      return expandName(p);
    else
      return allocStr(p, -1);
}

#ifdef __EMX__
static int
getcntrl(void)
{
    switch (
#ifdef MANY_CHARSET
          getch_internal(0)
#else
          getch()
#endif
          ) {
    case K_DEL:
      return CTRL_D;
    case K_LEFT:
      retrun CTRL_B;
    case K_RIGHT:
      return CTRL_F;
    case K_UP:
      return CTRL_P;
    case K_DOWN:
      return CTRL_N;
    case K_HOME:
    case K_CTRL_LEFT:
      return CTRL_A;
    case K_END:
    case K_CTRL_RIGHT:
      return CTRL_E;
    case K_CTRL_HOME:
      return CTRL_U;
    case K_CTRL_END:
      return CTRL_K;
    }
#ifdef MANY_CHARSET
    process_getch_mode(GETCH_MODE_CLR);
#endif
    return 0;
}
#endif

static void
addPasswd(char *p, Lineprop *pr, int len, int offset, int limit)
{
    int rcol = 0, ncol;

    ncol = calcPosition(p, pr, len, len, 0, CP_AUTO);
    if (ncol> offset + limit)
      ncol = offset + limit;
    if (offset) {
      addChar('{', 0);
      rcol = offset + 1;
    }
    for (; rcol < ncol; rcol++)
      addChar('*', 0);
}

static void
addStr(char *p, Lineprop *pr, int len, int offset, int limit)
{
    int i = 0, rcol = 0, ncol, delta = 1;
#ifdef MANY_CHARSET
    size_t b, e;
    mb_wchar_t wc;
#endif

    if (offset) {
      for (i = 0; i < len; i++) {
          if (calcPosition(p, pr, len, i, 0, CP_AUTO) > offset)
            break;
      }
      if (i >= len)
          return;
#ifdef MANY_CHARSET
      b = i;
      e = len;
      mb_mem_to_wchar(p, &b, &e);
      if (b < i)
          i = e;
#endif
#ifdef JP_CHARSET
      while (pr[i] == PC_KANJI2)
          i++;
#endif
      addChar('{', 0);
      rcol = offset + 1;
      ncol = calcPosition(p, pr, len, i, 0, CP_AUTO);
      for (; rcol < ncol; rcol++)
          addChar(' ', 0);
    }
    for (; i < len; i += delta) {
#ifdef JP_CHARSET
      if (CharType(pr[i]) == PC_KANJI1)
          delta = 2;
      else
          delta = 1;
#endif
#ifdef MANY_CHARSET
      if ((delta = mb_mem_to_wchar_internal(&p[i], len - i, wc)) < 0)
          delta = 1;
#endif
      ncol = calcPosition(p, pr, len, i + delta, 0, CP_AUTO);
      if (ncol - offset > limit)
          break;
      if (p[i] == '\t') {
          for (; rcol < ncol; rcol++)
            addChar(' ', 0);
          continue;
#ifdef JP_CHARSET
      } else if (delta == 2) {
          addChar(p[i], pr[i]);
          addChar(p[i+1], pr[i+1]);
#endif
      } else
#ifdef MANY_CHARSET
          addWChar(wc, ttyfix_wchar_width(wc), pr[i]);
#else
      addChar(p[i], pr[i]);
#endif
      rcol = ncol;
    }
}

#ifdef JP_CHARSET
static void
ins_kanji(Str tmp, InputLineEnv *env)
{
    if (tmp->length != 2)
      return;
    insC(env);
    env->strBuf->ptr[env->CPos] = tmp->ptr[0];
    env->strProp[env->CPos] = PC_KANJI1;
    (env->CPos)++;
    insC(env);
    env->strBuf->ptr[env->CPos] = tmp->ptr[1];
    env->strProp[env->CPos] = PC_KANJI2;
    (env->CPos)++;
}
#endif

void
linein_esc(int key, InputLineEnv *env)
{
    char c;
#ifdef JP_CHARSET
    char c2;
#endif

    switch (c =
#ifdef MANY_CHARSET
          getch_internal(0)
#else
          getch()
#endif
          ) {
    case '[':
    case 'O':
      c =
#ifdef MANY_CHARSET
          getch_internal(0)
#else
          getch()
#endif
          ;
#ifdef __CYGWIN__
      if ((is_xterm & (NEED_CYGWIN_ON | NEED_CYGWIN_OFF)) == NEED_CYGWIN_ON &&
          c == 'M') {
          getch();
          getch();
          getch();
          break;
      }
#endif
      call_edit_func_nostroke(K_ESCB | c, NULL, env);
      break;
    case CTRL_I:
    case ' ':
#ifdef EMACS_LIKE_LINEEDIT
      if (emacs_like_lineedit) {
          _rdcompl(env);
          env->cm_clear = FALSE;
          env->need_redraw = TRUE;
      }
      else
#endif
          _rcompl(env);
      break;
    case CTRL_D:
#ifdef EMACS_LIKE_LINEEDIT
      if (!emacs_like_lineedit)
#endif
          _rdcompl(env);
      env->need_redraw = TRUE;
      break;
#ifdef EMACS_LIKE_LINEEDIT
    case 'f':
      if (!emacs_like_lineedit)
          goto not_emacs_like;
      linein_mvRw(c, env);
      break;
    case 'b':
      if (!emacs_like_lineedit)
          goto not_emacs_like;
      linein_mvLw(c, env);
      break;
    case CTRL_H:
      if (!emacs_like_lineedit)
          goto not_emacs_like;
      linein_bsw(c, env);
      break;
#endif
#ifdef JP_CHARSET
    case '$':
      /* ISO-2022-jp characters */
      c2 = getch();
      env->in_kanji = TRUE;
      break;
    case '(':
      /* ISO-2022-jp characters */
      c2 = getch();
      env->in_kanji = FALSE;
      break;
#endif
    default:
#ifdef EMACS_LIKE_LINEEDIT
          not_emacs_like:
#endif
      call_edit_func_nostroke(K_ESC | c, NULL, env);
      break;
    }
}

#ifdef MANY_CHARSET
static void
insMBC(size_t cn, InputLineEnv *env)
{
    char tmp[MB_MBC_LEN_MAX + 1];

    memset(tmp, ' ', cn);
    tmp[cn] = '\0';
    Strinsert_charp(env->strBuf, env->CPos, tmp);
    env->CLen = env->strBuf->length;
    memmove(&env->strProp[env->CPos + cn], &env->strProp[env->CPos], sizeof(Lineprop) * cn);
}
#endif

static void
insC(InputLineEnv *env)
{
    int i;

    Strinsert_char(env->strBuf, env->CPos, ' ');
    env->CLen = env->strBuf->length;
    for (i = env->CLen; i > env->CPos; i--) {
      env->strProp[i] = env->strProp[i - 1];
    }
}

void
linein_delC(int key, InputLineEnv *env)
{
    int i = env->CPos;
    int delta = 1;
#ifdef MANY_CHARSET
    mb_wchar_t wc;
#endif

    if (env->CLen == env->CPos)
      return;
#ifdef MANY_CHARSET
    if ((delta = mb_mem_to_wchar_internal(&env->strBuf->ptr[env->CPos], env->CLen - env->CPos, wc)) < 0)
      delta = 1;
#endif
#ifdef JP_CHARSET
    if (env->strProp[i] == PC_KANJI1)
      delta = 2;
#endif                        /* JP_CHARSET */
    for (i = env->CPos; i < env->CLen; i++) {
      env->strProp[i] = env->strProp[i + delta];
    }
    Strdelete(env->strBuf, env->CPos, delta);
    env->CLen -= delta;
}

void
linein_mvL(int key, InputLineEnv *env)
{
#ifdef MANY_CHARSET
    if (env->CPos > 0) {
      size_t b = env->CPos - 1;
      size_t e = env->CLen;

      mb_mem_to_wchar(env->strBuf->ptr, &b, &e);
      env->CPos = b;
    }
#else
    if (env->CPos > 0)
      (env->CPos)--;
#ifdef JP_CHARSET
    if (env->strProp[env->CPos] == PC_KANJI2)
      (env->CPos)--;
#endif                        /* JP_CHARSET */
#endif
}

int
find_Lw(InputLineEnv *env)
{
    if (env->CPos > 0) {
#ifdef MANY_CHARSET
      size_t b, e;
      mb_wchar_t first, cur;
#else
      int b, first, cur;
#endif
      int word;

      word = env->CPos - 1;
#ifdef MANY_CHARSET
      e = env->CPos;
      first = mb_mem_to_wchar(env->strBuf->ptr, &word, &e);
#else
#ifdef JP_CHARSET
      if (env->strProp[word] == PC_KANJI2 && word > 0)
          --word;
#endif
      first = mctowc(&env->strBuf->ptr[word], env->strProp[word]);
#endif

      while (word > 0) {
          b = word - 1;
#ifdef MANY_CHARSET
          e = word;
          cur = mb_mem_to_wchar(env->strBuf->ptr, &b, &e);
#else
#ifdef JP_CHARSET
          if (env->strProp[b] == PC_KANJI2 && b > 0)
            --b;
#endif
          cur = mctowc(&env->strBuf->ptr[b], env->strProp[b]);
#endif

          if (!env->same_type_char_p(cur, first))
            break;

          word = b;
      }

      return word;
    }
    else
      return env->CPos;
}

void
linein_mvLw(int key, InputLineEnv *env)
{
    env->CPos = find_Lw(env);
}

static int
find_Rw(InputLineEnv *env)
{
    if (env->CPos < env->CLen) {
#ifdef MANY_CHARSET
      size_t b, e;
      mb_wchar_t first, cur;
#else
      int e, first, cur;
#endif
      int word;

#ifdef MANY_CHARSET
      b = env->CPos;
      e = env->CLen;
      first = mb_mem_to_wchar(env->strBuf->ptr, &b, &e);
      word = e;
#else
      word = env->CPos + get_mclen(env->strProp[env->CPos]);
      first = mctowc(&env->strBuf->ptr[env->CPos], env->strProp[env->CPos]);
#endif

      while (word < env->CLen) {
#ifdef MANY_CHARSET
          b = word;
          e = env->CLen;
          cur = mb_mem_to_wchar(env->strBuf->ptr, &b, &e);
#else
          e = word + get_mclen(env->strProp[word]);
          cur = mctowc(&env->strBuf->ptr[word], env->strProp[word]);
#endif

          if (!env->same_type_char_p(cur, first))
            break;

          word = e;
      }

      return word;
    }
    else
      return env->CPos;
}

void
linein_mvRw(int key, InputLineEnv *env)
{
    env->CPos = find_Rw(env);
}

void
linein_mvR(int key, InputLineEnv *env)
{
#ifdef MANY_CHARSET
    if (env->CPos < env->CLen) {
      size_t b = env->CPos;
      size_t e = env->CLen;

      mb_mem_to_wchar(env->strBuf->ptr, &b, &e);
      env->CPos = e;
    }
#else
    if (env->CPos < env->CLen)
      env->CPos++;
#ifdef JP_CHARSET
    if (env->strProp[env->CPos] == PC_KANJI2)
      env->CPos++;
#endif                        /* JP_CHARSET */
#endif
}

void
linein_bs(int key, InputLineEnv *env)
{
    if (env->CPos > 0) {
      linein_mvL(key, env);
      linein_delC(key, env);
    }
}

void
linein_bsw(int key, InputLineEnv *env)
{
    int word;

    if ((word = find_Lw(env)) < env->CPos) {
      memmove(&env->strProp[word], &env->strProp[env->CPos], sizeof(Lineprop) * (env->CPos - word));
      Strdelete(env->strBuf, word, env->CPos - word);
      env->CLen -= env->CPos - word;
      env->CPos = word;
    }
}

void
linein_delRw(int key, InputLineEnv *env)
{
    int word;

    if ((word = find_Rw(env)) > env->CPos) {
      memmove(&env->strProp[env->CPos], &env->strProp[word], sizeof(Lineprop) * (word - env->CPos));
      Strdelete(env->strBuf, env->CPos, word - env->CPos);
      env->CLen -= word - env->CPos;
    }
}

void
linein_enter(int key, InputLineEnv *env)
{
    env->i_cont = FALSE;
}

void
insertself(char c, InputLineEnv *env)
{
    if (env->CLen >= STR_LEN)
      return;
    insC(env);
    env->strBuf->ptr[env->CPos] = c;
    env->strProp[env->CPos] = env->is_passwd ? PC_ASCII : PC_CTRL;
    env->CPos++;
}

void
linein_quo(int key, InputLineEnv *env)
{
    env->i_quote = TRUE;
}

void
linein_mvB(int key, InputLineEnv *env)
{
    env->CPos = 0;
}

void
linein_mvE(int key, InputLineEnv *env)
{
    env->CPos = env->CLen;
}

void
linein_killn(int key, InputLineEnv *env)
{
    env->CLen = env->CPos;
    Strtruncate(env->strBuf, env->CLen);
}

void
linein_killb(int key, InputLineEnv *env)
{
    while (env->CPos > 0)
      linein_bs(key, env);
}

void
linein_inbrk(int key, InputLineEnv *env)
{
    env->i_cont = FALSE;
    env->i_broken = TRUE;
}

void
linein_compl(int key, InputLineEnv *env)
{
    next_compl(1, env);
}

static void
_rcompl(InputLineEnv *env)
{
    next_compl(-1, env);
}

void
linein_tcompl(int key, InputLineEnv *env)
{
    if (!(env->cm_mode & CPL_IMMUTABLE) && env->do_complete)
      env->cm_mode ^= CPL_ON;
}

static void
next_compl(int next, InputLineEnv *env)
{
    int status;
    int b, a;
    Str buf;
    Str s;

    if (!(env->cm_mode & CPL_ON) || !env->do_complete)
      return;
    env->cm_clear = FALSE;
    if (!env->cm_next) {
      if (env->cm_mode & CPL_WORDS) {
          for (b = env->CPos - 1; b >= 0; b--) {
            if ((env->strBuf->ptr[b] == ' ' || env->strBuf->ptr[b] == CTRL_I) &&
                !((b > 0) && env->strBuf->ptr[b - 1] == '\\'))
                break;
          }
          b++;
      }
      else 
          b = 0;
      a = env->CPos;
      env->CBeforeBuf = Strsubstr(env->strBuf, 0, b);
      buf = Strsubstr(env->strBuf, b, a - b);
      env->CAfterBuf = Strsubstr(env->strBuf, a, env->strBuf->length - a);
      s = env->do_complete(buf, &status, next, env);
    }
    else {
      s = env->do_complete(env->strBuf, &status, next, env);
    }
    if (next == 0)
      return;

    if (status != CPL_OK && status != CPL_MENU)
      bell();
    if (status == CPL_FAIL)
      return;

    env->strBuf = Strnew_m_charp(env->CBeforeBuf->ptr, s->ptr, env->CAfterBuf->ptr, NULL);
    env->CLen = setStrType(env);
    env->CPos = env->CBeforeBuf->length + s->length;
    if (env->CPos > env->CLen)
      env->CPos = env->CLen;
}

static void
_dcompl(InputLineEnv *env)
{
    next_dcompl(1, env);
}

static void
_rdcompl(InputLineEnv *env)
{
    next_dcompl(-1, env);
}

void
next_dcompl(int next, InputLineEnv *env)
{
    int i, j, n, y;
    int comment, nline;

    if (!(env->cm_mode & CPL_ON) || !env->do_complete)
      return;
    env->cm_disp_clear = FALSE;
    if (Currentbuf) {
      next_dcompl_top = -1;
      next_dcompl_env = NULL;
      displayCurrentView(NULL);
    }

    if (LASTLINE >= 3) {
      comment = TRUE;
      nline = LASTLINE - 2;
    } else if (LASTLINE) {
      comment = FALSE;
      nline = LASTLINE;
    } else {
      return;
    }
    if (env->cm_disp_next >= 0) {
      if (next == 1) {
          env->cm_disp_next += env->dcompl_env.col * nline;
          if (env->cm_disp_next >= env->NCandBuf)
            env->cm_disp_next = 0;
      }
      else if (next == -1) {
          env->cm_disp_next -= env->dcompl_env.col * nline;
          if (env->cm_disp_next < 0)
            env->cm_disp_next = 0;
      }
      env->dcompl_env.row = (env->NCandBuf - env->cm_disp_next + env->dcompl_env.col - 1) / env->dcompl_env.col;
      goto disp_next;
    }

    env->cm_next = FALSE;
    next_compl(0, env);
    if (env->NCandBuf == 0)
      return;
    env->cm_disp_next = 0;

    env->dcompl_env.len = 0;
    for (i = 0; i < env->NCandBuf; i++) {
#ifdef MANY_CHARSET
      n = ttyfix_width(env->CandBuf[i]) + 3;
#else
      n = strlen(env->CandBuf[i]) + 3;
#endif
      if (env->dcompl_env.len < n)
          env->dcompl_env.len = n;
    }
    env->dcompl_env.col = COLS / env->dcompl_env.len;
    if (env->dcompl_env.col == 0)
      env->dcompl_env.col = 1;
    env->dcompl_env.row = (env->NCandBuf + env->dcompl_env.col - 1) / env->dcompl_env.col;

disp_next:
    if (comment) {
      if (env->dcompl_env.row > nline) {
          env->dcompl_env.row = nline;
          y = 0;
      } else
          y = nline - env->dcompl_env.row + 1;
    } else {
      if (env->dcompl_env.row >= nline) {
          env->dcompl_env.row = nline;
          y = 0;
      } else
          y = nline - env->dcompl_env.row - 1;
    }
    if (y) {
      next_dcompl_top = y - 1;
      move(y - 1, 0);
      clrtoeolx();
    }
    else
      next_dcompl_top = y;
    next_dcompl_next = next;
    next_dcompl_env = env;
    if (comment) {
      move(y, 0);
      clrtoeolx();
      bold();
      addstr("----- Completion list -----");
      boldend();
      y++;
    }
    for (i = 0; i < env->dcompl_env.row; i++) {
      for (j = 0; j < env->dcompl_env.col; j++) {
          n = env->cm_disp_next + j * env->dcompl_env.row + i;
          if (n >= env->NCandBuf)
            break;
          move(y, j * env->dcompl_env.len);
          clrtoeolx();
          addstr(env->CandBuf[n]);
      }
      y++;
    }
    if (comment && y == LASTLINE - 1) {
      move(y, 0);
      clrtoeolx();
      bold();
#ifdef EMACS_LIKE_LINEEDIT
      if (emacs_like_lineedit)
          addstr("----- Press TAB to continue -----");
      else
#endif
          addstr("----- Press CTRL-D to continue -----");
      boldend();
    }
}

static Str
escape_spaces(Str s)
{
    Str tmp = NULL;
    char *p;

    if (s == NULL)
      return s;
    for (p = s->ptr; *p; p++) {
      if (*p == ' ' || *p == CTRL_I) {
          if (tmp == NULL)
            tmp = Strnew_charp_n(s->ptr, (int)(p - s->ptr));
          Strcat_char(tmp, '\\');
      }
      if (tmp)
          Strcat_char(tmp, *p);
    }
    if (tmp)
      return tmp;
    return s;
}

Str
unescape_spaces(Str s)
{
    Str tmp = NULL;
    char *p;

    if (s == NULL)
      return s;
    for (p = s->ptr; *p; p++) {
      if (*p == '\\' && (*(p + 1) == ' ' || *(p + 1) == CTRL_I)) {
          if (tmp == NULL)
            tmp = Strnew_charp_n(s->ptr, (int)(p - s->ptr));
      }
      else {
          if (tmp)
            Strcat_char(tmp, *p);
      }
    }
    if (tmp)
      return tmp;
    return s;
}

static Str
do_filename_complete(Str ifn, int *status, int next, InputLineEnv *env)
{
    ComplFileNameEnv *cfn;
    int fl, i;
    char *fn, *p;
    DIR *d;
    Directory *dir;
    struct stat st;

    cfn = env->ComplPrivate;

    if (!env->cm_next) {
      int url_part = 0;

      env->NCandBuf = 0;
      ifn = Str_conv_to_system(ifn);
      if (env->cm_mode & CPL_COMMAND)
          ifn = unescape_spaces(ifn);
      env->CompleteBuf = Strdup(ifn);
      while (Strlastchar(env->CompleteBuf) != '/' &&
             env->CompleteBuf->length > 0)
          Strshrink(env->CompleteBuf, 1);
      cfn->CDirBuf = Strdup(env->CompleteBuf);
      if (env->cm_mode & CPL_URL) {
          if (strncmp(env->CompleteBuf->ptr, "file://localhost/", sizeof("file://localhost/") - 1) == 0)
            url_part = sizeof("file://localhost/") - sizeof("/");
          else if (strncmp(env->CompleteBuf->ptr, "file:///", sizeof("file:///") - 1) == 0)
            url_part = sizeof("file:///") - sizeof("/");
          else if (strncmp(env->CompleteBuf->ptr, "file:/", sizeof("file:/") - 1) == 0 &&
                 env->CompleteBuf->ptr[sizeof("file:/") - 1] != '/')
            url_part = sizeof("file:/") - sizeof("/");
          else
            goto not_a_filename;
          Strdelete(env->CompleteBuf, 0, url_part);
      }
      if (env->CompleteBuf->length == 0) {
          Strcat_char(env->CompleteBuf, '.');
      }
      if (Strlastchar(env->CompleteBuf) == '/' && env->CompleteBuf->length > 1) {
          Strshrink(env->CompleteBuf, 1);
      }
      if (!(d = opendir(expandName(env->CompleteBuf->ptr))))
          goto not_a_filename;
      fn = lastFileName(ifn->ptr);
      fl = strlen(fn);
      cfn->CFileName = Strnew();
      for (;;) {
          dir = readdir(d);
          if (dir == NULL)
            break;
          if (fl == 0 && (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")))
            continue;
          if (!strncmp(dir->d_name, fn, fl)) {  /* match */
            Str fn, path;

            fn = Str_conv_from_system(Strnew_charp(dir->d_name));
            path = Strdup(cfn->CDirBuf);
            if (path->length == 0)
                Strcat(path, fn);
            else {
                if (Strlastchar(path) != '/')
                  Strcat_char(path, '/');
                Strcat(path, fn);
            }
            if (*status != CPL_AMBIG) {
                p = path->ptr;
                if (url_part)
                  p += url_part;
                if (stat(expandName(p), &st) != -1 && S_ISDIR(st.st_mode))
                  Strcat_char(fn, '/');
            }
            (env->NCandBuf)++;
            env->CandBuf = New_Reuse(char *, env->CandBuf, env->NCandBuf);
            env->CandBuf[env->NCandBuf - 1] = NewAtom_N(char, fn->length + 1);
            strcpy(env->CandBuf[env->NCandBuf - 1], fn->ptr);
            if (env->NCandBuf == 1) {
                cfn->CFileName = Strdup(fn);
            }
            else {
                for (i = 0; i < fn->length && i < cfn->CFileName->length && cfn->CFileName->ptr[i] == fn->ptr[i]; i++);
                Strtruncate(cfn->CFileName, i);
            }
          }
      }
      closedir(d);
      if (env->NCandBuf == 0) {
      not_a_filename:
          if (env->CurrentHist) {
            Str d;

            d = do_hist_complete(ifn, status, next, env);

            if (*status != CPL_FAIL)
                return d;
          }

          env->CompleteBuf = Strdup(ifn);
          *status = CPL_FAIL;
          if (env->cm_mode & CPL_COMMAND)
            env->CompleteBuf = escape_spaces(env->CompleteBuf);
          return Strdup(env->CompleteBuf);
      }
      qsort(env->CandBuf, env->NCandBuf, sizeof(env->CandBuf[0]), strCmp);
      env->NCandOffset = 0;
      if (env->NCandBuf >= 2) {
          env->cm_next = TRUE;
          *status = CPL_AMBIG;
      }
      else {
          *status = CPL_OK;
      }
    }
    else {
      cfn->CFileName = Strnew_charp(env->CandBuf[env->NCandOffset]);
      env->NCandOffset = (env->NCandOffset + next + env->NCandBuf) % env->NCandBuf;
      *status = CPL_MENU;
    }
    env->CompleteBuf = Strdup(cfn->CDirBuf);
    if (env->CompleteBuf->length == 0)
      Strcat(env->CompleteBuf, cfn->CFileName);
    else if (Strlastchar(env->CompleteBuf) == '/')
      Strcat(env->CompleteBuf, cfn->CFileName);
    else {
      Strcat_char(env->CompleteBuf, '/');
      Strcat(env->CompleteBuf, cfn->CFileName);
    }
    if (*status != CPL_AMBIG && Strlastchar(env->CompleteBuf) != '/') {
      p = env->CompleteBuf->ptr;
      if (env->cm_mode & CPL_URL) {
          if (strncmp(p, "file://localhost/", sizeof("file://localhost/") - 1) == 0)
            p += sizeof("file://localhost/") - sizeof("/");
          else if (strncmp(p, "file:///", sizeof("file:///") - 1) == 0)
            p += sizeof("file:///") - sizeof("/");
          else if (strncmp(p, "file:/", sizeof("file:/") - 1) == 0 && p[sizeof("file:/") - 1] != '/')
            p += sizeof("file:/") - sizeof("/");
      }
      if (stat(expandName(p), &st) != -1 && S_ISDIR(st.st_mode))
          Strcat_char(env->CompleteBuf, '/');
    }
    if (env->cm_mode & CPL_COMMAND)
      env->CompleteBuf = escape_spaces(env->CompleteBuf);
    return Strdup(env->CompleteBuf);
}

static Str
do_hist_complete(Str ifn, int *status, int next, InputLineEnv *env)
{
    int fl, i;

    if (!env->cm_next) {
      Hist *hist;

      env->NCandBuf = 0;

      if ((hist = env->CurrentHist) && hist->list) {
          HistItem *hi;
          Str s = NULL;

          for (hi = hist->current ? hist->current : hist->list->last ; hi ; hi = hi->prev) {
            if (!strncmp(hi->ptr, ifn->ptr, ifn->length)) {
                char *p;

                p = hi->ptr;
                fl = strlen(p);
                (env->NCandBuf)++;
                env->CandBuf = New_Reuse(char *, env->CandBuf, env->NCandBuf);
                env->CandBuf[env->NCandBuf - 1] = NewAtom_N(char, fl + 1);
                strcpy(env->CandBuf[env->NCandBuf - 1], p);

                if (!s)
                  s = Strnew_charp_n(p, fl);
                else {
                  for (i = ifn->length ; i < fl && i < s->length && p[i] == s->ptr[i] ; ++i)
                      ;

                  Strtruncate(s, i);
                }
            }
          }

          env->CompleteBuf = s;
      }

      if (env->NCandBuf == 0) {
          env->CompleteBuf = Strdup(ifn);
          *status = CPL_FAIL;
          return Strdup(env->CompleteBuf);
      }

      qsort(env->CandBuf, env->NCandBuf, sizeof(env->CandBuf[0]), strCmp);
      env->NCandOffset = 0;

      if (env->NCandBuf >= 2) {
          env->cm_next = TRUE;
          *status = CPL_AMBIG;
      }
      else {
          *status = CPL_OK;
      }
    }
    else {
      env->NCandOffset = (env->NCandOffset + next + env->NCandBuf) % env->NCandBuf;
      *status = CPL_MENU;
    }

    return Strdup(env->CompleteBuf);
}

struct do_tab_complete_arg {
    Str ifn;
    Str s;
    InputLineEnv *env;
    btri_key_cursor_t key;
};

static void
do_ci_tab_complete_loop(btri_string_tab_t *node, struct do_tab_complete_arg *p)
{
    if (node) {
      int i, j, n;
      char *q;

      for (i = 0 ; i < 2 ; ++i)
          switch (node->type[i]) {
          case bt_failure:
            break;
          case bt_node:
            do_ci_tab_complete_loop(node->value[i], p);
            break;
          default:
            if (node->key[i].n >= p->key.n &&
                !strncasecmp(node->key[i].base, p->ifn->ptr, p->ifn->length)) {
                (p->env->NCandBuf)++;
                p->env->CandBuf = New_Reuse(char *, p->env->CandBuf, p->env->NCandBuf);
                n = node->key[i].n / CHAR_BIT;
                p->env->CandBuf[p->env->NCandBuf - 1] = q = allocStr(node->key[i].base, n);

                if (!p->s)
                  p->s = Strnew_charp_n(q, n);
                else {
                  for (j = p->ifn->length ; j < n && j < p->s->length && q[j] == p->s->ptr[j] ; ++j)
                      ;

                  Strtruncate(p->s, j);
                }
            }

            break;
          }
    }
}

static Str
do_ci_tab_complete(Str ifn, int *status, int next, InputLineEnv *env)
{
    if (!env->cm_next) {
      env->NCandBuf = 0;

      if (env->ComplPrivate) {
          struct do_tab_complete_arg e;

          e.ifn = ifn;
          e.s = NULL;
          e.env = env;
          e.key.base = ifn->ptr;
          e.key.n = ifn->length * CHAR_BIT;
          do_ci_tab_complete_loop(env->ComplPrivate, &e);
          env->CompleteBuf = e.s;
      }

      if (env->NCandBuf == 0) {
          env->CompleteBuf = Strdup(ifn);
          *status = CPL_FAIL;
          return Strdup(env->CompleteBuf);
      }

      qsort(env->CandBuf, env->NCandBuf, sizeof(env->CandBuf[0]), strCmp);
      env->NCandOffset = 0;

      if (env->NCandBuf >= 2) {
          env->cm_next = TRUE;
          *status = CPL_AMBIG;
      }
      else {
          *status = CPL_OK;
      }
    }
    else {
      env->NCandOffset = (env->NCandOffset + next + env->NCandBuf) % env->NCandBuf;
      *status = CPL_MENU;
    }

    return Strdup(env->CompleteBuf);
}

void
linein_prev(int key, InputLineEnv *env)
{
    Hist *hist = env->CurrentHist;
    char *p;

    if (! env->use_hist)
      return;
    if (env->strCurrentBuf) {
      p = prevHist(hist);
      if (p == NULL)
          return;
    } else {
      p = lastHist(hist);
      if (p == NULL)
          return;
      env->strCurrentBuf = env->strBuf;
    }
    env->strBuf = Strnew_charp(p);
    env->CLen = env->CPos = setStrType(env);
    env->offset = 0;
}

void
linein_next(int key, InputLineEnv *env)
{
    Hist *hist = env->CurrentHist;
    char *p;

    if (! env->use_hist)
      return;
    if (env->strCurrentBuf == NULL)
      return;
    p = nextHist(hist);
    if (p) {
      env->strBuf = Strnew_charp(p);
    } else {
      env->strBuf = env->strCurrentBuf;
      env->strCurrentBuf = NULL;
    }
    env->CLen = env->CPos = setStrType(env);
    env->offset = 0;
}

void
linein_copyregion(int key, InputLineEnv *env)
{
#ifdef USE_MARK
    char *p;

    if (Currentbuf && (p = GetMarkedRegion(Currentbuf, NULL, NULL, NULL, NULL)) && *p) {
      while (*p) {
          insC(env);
          env->strBuf->ptr[(env->CPos)++] = *p++;
      }

      env->CLen = setStrType(env);

      if (env->CPos > env->CLen)
          env->CPos = env->CLen;
    }
#endif
    ;
}

void
linein_nextchar(int key, InputLineEnv *env)
{
    call_edit_func(
#ifdef MANY_CHARSET
               getch_internal(0)
#else
               getch()
#endif
               , NULL, env);
}

static int
setStrType(InputLineEnv *env)
{
    Lineprop ctype;
#ifdef MANY_CHARSET
    mb_wchar_t wc;
#endif
    int i = 0, delta;
    char *s = env->strBuf->ptr;

    for (; *s != '\0' && i < STR_LEN; s += delta, i += delta) {
      ctype = get_mctype(s);
      if (env->is_passwd && ctype & PC_CTRL)
          ctype = PC_ASCII;
#ifdef MANY_CHARSET
      if ((delta = mb_mem_to_wchar_internal(s, STR_LEN - i, wc)) == MB_MBC_LEN_MAX) {
          memset(&env->strProp[i], ctype, MB_MBC_LEN_MAX);
          continue;
      }
      delta = 1;
#else
      delta = get_mclen(ctype);
#ifdef JP_CHARSET
      if (ctype == PC_KANJI) {
          env->strProp[i] = PC_KANJI1;
          env->strProp[i+1] = PC_KANJI2;
      }
      else
#endif
#endif
          env->strProp[i] = ctype;
    }
    return i;
}

/* Local Variables:    */
/* c-basic-offset: 4   */
/* tab-width: 8        */
/* End:                */

Generated by  Doxygen 1.6.0   Back to index