"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.3/src/getline.c" (23 Nov 2018, 18348 Bytes) of package /linux/misc/tin-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "getline.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.2_vs_2.4.3.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : getline.c
    4  *  Author    : Chris Thewalt & Iain Lea
    5  *  Created   : 1991-11-09
    6  *  Updated   : 2018-02-06
    7  *  Notes     : emacs style line editing input package.
    8  *  Copyright : (c) Copyright 1991-99 by Chris Thewalt & Iain Lea
    9  *              Permission to use, copy, modify, and distribute this
   10  *              software for any purpose and without fee is hereby
   11  *              granted, provided that the above copyright notices
   12  *              appear in all copies and that both the copyright
   13  *              notice and this permission notice appear in supporting
   14  *              documentation. This software is provided "as is" without
   15  *              express or implied warranty.
   16  */
   17 
   18 #ifndef TIN_H
   19 #   include "tin.h"
   20 #endif /* !TIN_H */
   21 #ifndef TCURSES_H
   22 #   include "tcurses.h"
   23 #endif /* !TCURSES_H */
   24 
   25 #define BUF_SIZE    1024
   26 #define TAB_SIZE        4
   27 
   28 #define CTRL_A  '\001'
   29 #define CTRL_B  '\002'
   30 #define CTRL_D  '\004'
   31 #define CTRL_E  '\005'
   32 #define CTRL_F  '\006'
   33 #define CTRL_H  '\010'
   34 #define CTRL_K  '\013'
   35 #define CTRL_L  '\014'
   36 #define CTRL_R  '\022'
   37 #define CTRL_N  '\016'
   38 #define CTRL_P  '\020'
   39 #define CTRL_U  '\025'
   40 #define CTRL_W  '\027'
   41 #define TAB '\t'
   42 #define DEL '\177'
   43 
   44 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
   45     static wchar_t gl_buf[BUF_SIZE];    /* wide-character input buffer */
   46     static char buf[BUF_SIZE];
   47 #else
   48     static char gl_buf[BUF_SIZE];   /* input buffer */
   49 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
   50 static int gl_init_done = 0;    /* -1 is terminal, 1 is batch */
   51 static const char *gl_prompt;   /* to save the prompt string */
   52 static int gl_width = 0;    /* net size available for input */
   53 static int gl_pos, gl_cnt = 0;  /* position and size of input */
   54 static t_bool is_passwd;
   55 
   56 /*
   57  * local prototypes
   58  */
   59 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
   60     static void gl_addwchar(wint_t wc);
   61     static int gl_tab(wchar_t *wbuf, int offset, int *loc);
   62 #else
   63     static void gl_addchar(int c);
   64     static int gl_tab(char *buf, int offset, int *loc);
   65 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
   66 static void gl_del(int loc);
   67 static void gl_fixup(int change, int cursor);
   68 static void gl_newline(int w);
   69 static void gl_kill(void);
   70 static void gl_kill_back_word(void);
   71 static void hist_add(int w);
   72 static void hist_next(int w);
   73 static void hist_prev(int w);
   74 
   75 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
   76     static int (*gl_in_hook) (wchar_t *) = 0;
   77     static int (*gl_out_hook) (wchar_t *) = 0;
   78     static int (*gl_tab_hook) (wchar_t *, int, int *) = gl_tab;
   79 #else
   80     static int (*gl_in_hook) (char *) = 0;
   81     static int (*gl_out_hook) (char *) = 0;
   82     static int (*gl_tab_hook) (char *, int, int *) = gl_tab;
   83 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
   84 
   85 char *
   86 tin_getline(
   87     const char *prompt,
   88     int number_only,    /* 1=positive numbers only, 2=negative too */
   89     const char *str,
   90     int max_chars,
   91     t_bool passwd,
   92     int which_hist)
   93 {
   94     int c, i, loc, tmp, gl_max;
   95     char *tprompt;
   96 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
   97     wint_t wc;
   98 #else
   99     char *buf = gl_buf;
  100 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  101 
  102     input_context = cGetline;
  103 
  104     is_passwd = passwd;
  105 
  106     set_xclick_off();
  107     if (prompt == NULL)
  108         prompt = "";
  109 
  110     tprompt = strunc(prompt, cCOLS - 6);
  111 
  112     gl_buf[0] = 0;      /* used as end of input indicator */
  113     gl_fixup(-1, 0);    /* this resets gl_fixup */
  114     gl_width = cCOLS - MIN(cCOLS - 6, strwidth(tprompt));
  115     gl_prompt = tprompt;
  116     gl_pos = gl_cnt = 0;
  117 
  118     if (max_chars == 0) {
  119         if (number_only)
  120             gl_max = 6;
  121         else
  122             gl_max = BUF_SIZE;
  123     } else
  124         gl_max = max_chars;
  125 
  126     my_fputs(tprompt, stdout);
  127     cursoron();
  128     my_flush();
  129 
  130     if (gl_in_hook) {
  131         loc = gl_in_hook(gl_buf);
  132         if (loc >= 0)
  133             gl_fixup(0, BUF_SIZE);
  134     }
  135 
  136     if (!cmd_line && gl_max == BUF_SIZE)
  137         CleartoEOLN();
  138 
  139 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  140     if (str != NULL) {
  141         wchar_t *wbuf;
  142 
  143         if ((wbuf = char2wchar_t(str)) != NULL) {
  144             for (i = 0; wbuf[i]; i++)
  145                 gl_addwchar(wbuf[i]);
  146             free(wbuf);
  147         }
  148     }
  149 
  150     while ((wc = ReadWch()) != WEOF) {
  151         if ((gl_cnt < gl_max) && iswprint(wc)) {
  152             if (number_only) {
  153                 if (iswdigit(wc)) {
  154                     gl_addwchar(wc);
  155                 /* Minus */
  156                 } else if (number_only == 2 && gl_pos == 0 && wc == (wint_t) '-') {
  157                     gl_addwchar(wc);
  158                 } else {
  159                     ring_bell();
  160                 }
  161             } else
  162                 gl_addwchar(wc);
  163         } else {
  164             c = (int) wc;
  165             switch (wc) {
  166 #else
  167     if (str != NULL) {
  168         for (i = 0; str[i]; i++)
  169             gl_addchar(str[i]);
  170     }
  171 
  172     while ((c = ReadCh()) != EOF) {
  173         c &= 0xff;
  174         if ((gl_cnt < gl_max) && my_isprint(c)) {
  175             if (number_only) {
  176                 if (isdigit(c)) {
  177                     gl_addchar(c);
  178                 /* Minus */
  179                 } else if (number_only == 2 && gl_pos == 0 && c == '-') {
  180                     gl_addchar(c);
  181                 } else {
  182                     ring_bell();
  183                 }
  184             } else
  185                 gl_addchar(c);
  186         } else {
  187             switch (c) {
  188 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  189                 case ESC:   /* abort */
  190 #ifdef HAVE_KEY_PREFIX
  191                 case KEY_PREFIX:
  192 #endif /* HAVE_KEY_PREFIX */
  193                     switch (get_arrow_key(c)) {
  194                         case KEYMAP_UP:
  195                         case KEYMAP_PAGE_UP:
  196                             hist_prev(which_hist);
  197                             break;
  198 
  199                         case KEYMAP_PAGE_DOWN:
  200                         case KEYMAP_DOWN:
  201                             hist_next(which_hist);
  202                             break;
  203 
  204                         case KEYMAP_RIGHT:
  205                             gl_fixup(-1, gl_pos + 1);
  206                             break;
  207 
  208                         case KEYMAP_LEFT:
  209                             gl_fixup(-1, gl_pos - 1);
  210                             break;
  211 
  212                         case KEYMAP_HOME:
  213                             gl_fixup(-1, 0);
  214                             break;
  215 
  216                         case KEYMAP_END:
  217                             gl_fixup(-1, gl_cnt);
  218                             break;
  219 
  220                         case KEYMAP_DEL:
  221                             gl_del(0);
  222                             break;
  223 
  224                         case KEYMAP_INS:
  225 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  226                             gl_addwchar((wint_t) ' ');
  227 #else
  228                             gl_addchar(' ');
  229 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  230                             break;
  231 
  232                         default:
  233                             input_context = cNone;
  234                             free(tprompt);
  235                             return NULL;
  236                     }
  237                     break;
  238 
  239                 case '\n':  /* newline */
  240                 case '\r':
  241                     gl_newline(which_hist);
  242 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  243                     wcstombs(buf, gl_buf, BUF_SIZE - 1);
  244 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  245                     input_context = cNone;
  246                     free(tprompt);
  247                     return buf;
  248 
  249                 case CTRL_A:
  250                     gl_fixup(-1, 0);
  251                     break;
  252 
  253                 case CTRL_B:
  254                     gl_fixup(-1, gl_pos - 1);
  255                     break;
  256 
  257                 case CTRL_D:
  258                     if (gl_cnt == 0) {
  259                         gl_buf[0] = 0;
  260                         my_fputc('\n', stdout);
  261 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  262                         wcstombs(buf, gl_buf, BUF_SIZE - 1);
  263 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  264                         input_context = cNone;
  265                         free(tprompt);
  266                         return buf;
  267                     } else
  268                         gl_del(0);
  269                     break;
  270 
  271                 case CTRL_E:
  272                     gl_fixup(-1, gl_cnt);
  273                     break;
  274 
  275                 case CTRL_F:
  276                     gl_fixup(-1, gl_pos + 1);
  277                     break;
  278 
  279                 case CTRL_H:
  280                 case DEL:
  281                     gl_del(-1);
  282                     break;
  283 
  284                 case TAB:
  285                     if (gl_tab_hook) {
  286                         tmp = gl_pos;
  287                         loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp);
  288                         if (loc >= 0 || tmp != gl_pos)
  289                             gl_fixup(loc, tmp);
  290                     }
  291                     break;
  292 
  293                 case CTRL_W:
  294                     gl_kill_back_word();
  295                     break;
  296 
  297                 case CTRL_U:
  298                     gl_fixup(-1, 0);
  299                     /* FALLTHROUGH */
  300                 case CTRL_K:
  301                     gl_kill();
  302                     break;
  303 
  304                 case CTRL_L:
  305                 case CTRL_R:
  306                     gl_redraw();
  307                     break;
  308 
  309                 case CTRL_N:
  310                     hist_next(which_hist);
  311                     break;
  312 
  313                 case CTRL_P:
  314                     hist_prev(which_hist);
  315                     break;
  316 
  317                 default:
  318                     ring_bell();
  319                     break;
  320             }
  321         }
  322     }
  323 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  324     wcstombs(buf, gl_buf, BUF_SIZE - 1);
  325 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  326     input_context = cNone;
  327     free(tprompt);
  328     return buf;
  329 }
  330 
  331 
  332 /*
  333  * adds the character c to the input buffer at current location if
  334  * the character is in the allowed template of characters
  335  */
  336 static void
  337 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  338 gl_addwchar(
  339     wint_t wc)
  340 #else
  341 gl_addchar(
  342     int c)
  343 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  344 {
  345     int i;
  346 
  347     /*
  348      * Crashing is always the worst solution IMHO. So as a quick hack,
  349      * ignore characters silently, if buffer is full. To allow a final
  350      * newline, leave space for one more character. Just a hack too.
  351      * This was the original code:
  352      *
  353     if (gl_cnt >= BUF_SIZE - 1) {
  354         error_message(2, "tin_getline: input buffer overflow");
  355         giveup();
  356     }
  357      */
  358     if (gl_cnt >= BUF_SIZE - 2)
  359         return;
  360 
  361     for (i = gl_cnt; i >= gl_pos; i--)
  362         gl_buf[i + 1] = gl_buf[i];
  363 
  364 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  365     gl_buf[gl_pos] = (wchar_t) wc;
  366 #else
  367     gl_buf[gl_pos] = c;
  368 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  369     gl_fixup(gl_pos, gl_pos + 1);
  370 }
  371 
  372 
  373 /*
  374  * Cleans up entire line before returning to caller. A \n is appended.
  375  * If line longer than screen, we redraw starting at beginning
  376  */
  377 static void
  378 gl_newline(
  379     int w)
  380 {
  381     int change = gl_cnt;
  382     int len = gl_cnt;
  383     int loc = gl_width - 5; /* shifts line back to start position */
  384 
  385     if (gl_cnt >= BUF_SIZE - 1) {
  386         /*
  387          * Like above: avoid crashing if possible. gl_addchar() now
  388          * leaves one space left for the newline, so this part of the
  389          * code should never be reached. A proper implementation is
  390          * desirable though.
  391          */
  392         error_message(2, "tin_getline: input buffer overflow");
  393         free(tin_progname);
  394         giveup();
  395     }
  396     hist_add(w);        /* only adds if nonblank */
  397     if (gl_out_hook) {
  398         change = gl_out_hook(gl_buf);
  399 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  400         len = wcslen(gl_buf);
  401 #else
  402         len = strlen(gl_buf);
  403 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  404     }
  405     if (loc > len)
  406         loc = len;
  407     gl_fixup(change, loc);  /* must do this before appending \n */
  408 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  409     gl_buf[len] = (wchar_t) '\0';
  410 #else
  411     gl_buf[len] = '\0';
  412 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  413 }
  414 
  415 
  416 /*
  417  * Delete a character. The loc variable can be:
  418  *    -1 : delete character to left of cursor
  419  *     0 : delete character under cursor
  420  */
  421 static void
  422 gl_del(
  423     int loc)
  424 {
  425     int i;
  426 
  427     if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
  428         for (i = gl_pos + loc; i < gl_cnt; i++)
  429             gl_buf[i] = gl_buf[i + 1];
  430         gl_fixup(gl_pos + loc, gl_pos + loc);
  431     } else
  432         ring_bell();
  433 }
  434 
  435 
  436 /*
  437  * delete from current position to the end of line
  438  */
  439 static void
  440 gl_kill(
  441     void)
  442 {
  443     if (gl_pos < gl_cnt) {
  444 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  445         gl_buf[gl_pos] = (wchar_t) '\0';
  446 #else
  447         gl_buf[gl_pos] = '\0';
  448 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  449         gl_fixup(gl_pos, gl_pos);
  450     } else
  451         ring_bell();
  452 }
  453 
  454 
  455 /*
  456  * delete from the start of current or last word to current position
  457  */
  458 static void
  459 gl_kill_back_word(
  460     void)
  461 {
  462     int i, j, cur;
  463 
  464 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  465     /* delete spaces */
  466     for (i = gl_pos - 1; i >= 0 && iswspace((wint_t) gl_buf[i]); --i)
  467         ;
  468 
  469     /* delete not alnum characters but graph characters */
  470     for (; i >= 0 && iswgraph((wint_t) gl_buf[i]) && !iswalnum((wint_t) gl_buf[i]); --i)
  471         ;
  472 
  473     /* delete all graph characters except '/' */
  474     for (; i >= 0 && gl_buf[i] != (wchar_t) '/' && iswgraph((wint_t) gl_buf[i]); --i)
  475         ;
  476 #else
  477     /* delete spaces */
  478     for (i = gl_pos - 1; i >= 0 && isspace((int) gl_buf[i]); --i)
  479         ;
  480 
  481     /* delete not alnum characters but graph characters */
  482     for (; i >= 0 && isgraph((int) gl_buf[i]) && !isalnum((int) gl_buf[i]); --i)
  483         ;
  484 
  485     /* delete all graph characters except '/' */
  486     for (; i >= 0 && gl_buf[i] != '/' && isgraph((int) gl_buf[i]); --i)
  487         ;
  488 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  489 
  490     i++;
  491     if (i != gl_pos) {
  492         j = i;
  493         cur = gl_pos;
  494         gl_fixup(-1, i);
  495 
  496         while (gl_buf[cur])
  497             gl_buf[j++] = gl_buf[cur++];
  498 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  499         gl_buf[j] = (wchar_t) '\0';
  500 #else
  501         gl_buf[j] = '\0';
  502 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  503         gl_fixup(i, i);
  504     } else
  505         ring_bell();
  506 }
  507 
  508 
  509 /*
  510  * emit a newline, reset and redraw prompt and current input line
  511  */
  512 void
  513 gl_redraw(
  514     void)
  515 {
  516     if (gl_init_done == -1) {   /* terminal */
  517         my_fputc('\n', stdout);
  518         my_fputs(gl_prompt, stdout);
  519         gl_pos = 0;
  520         gl_fixup(0, BUF_SIZE);
  521     } else if (gl_init_done == 0) { /* screen */
  522         clear_message();
  523         my_fputs(gl_prompt, stdout);
  524         gl_pos = 0;
  525         gl_fixup(0, BUF_SIZE);
  526         cursoron();
  527     }
  528 }
  529 
  530 
  531 /*
  532  * This function is used both for redrawing when input changes or for
  533  * moving within the input line. The parameters are:
  534  *   change : the index of the start of changes in the input buffer,
  535  *            with -1 indicating no changes.
  536  *   cursor : the desired location of the cursor after the call.
  537  *            A value of BUF_SIZE can be used to indicate the cursor
  538  *            should move just past the end of the input line.
  539  */
  540 static void
  541 gl_fixup(
  542     int change,
  543     int cursor)
  544 {
  545     static int gl_shift;    /* index of first on screen character */
  546     static int off_right;   /* true if more text right of screen */
  547     static int off_left;    /* true if more text left of screen */
  548     int left = 0, right = -1;   /* bounds for redraw */
  549     int pad;        /* how much to erase at end of line */
  550     int backup;     /* how far to backup before fixing */
  551     int new_shift;      /* value of shift based on cursor */
  552     int extra;      /* adjusts when shift (scroll) happens */
  553     int i;
  554     /* FIXME: there are some small problems if SCROLL >= gl_width - 2 */
  555     int SCROLL = MIN(30, gl_width - 3);
  556 
  557     if (change == -1 && cursor == 0 && gl_buf[0] == 0) {    /* reset */
  558         gl_shift = off_right = off_left = 0;
  559         return;
  560     }
  561     pad = (off_right) ? gl_width - 1 : gl_cnt - gl_shift;   /* old length */
  562     backup = gl_pos - gl_shift;
  563     if (change >= 0) {
  564 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  565         gl_cnt = wcslen(gl_buf);
  566 #else
  567         gl_cnt = strlen(gl_buf);
  568 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  569         if (change > gl_cnt)
  570             change = gl_cnt;
  571     }
  572     if (cursor > gl_cnt) {
  573         if (cursor != BUF_SIZE)     /* BUF_SIZE means end of line */
  574             ring_bell();
  575         cursor = gl_cnt;
  576     }
  577     if (cursor < 0) {
  578         ring_bell();
  579         cursor = 0;
  580     }
  581     if (!is_passwd) {
  582         if (off_right || (off_left && (cursor < gl_shift + gl_width - SCROLL / 2)))
  583             extra = 2;  /* shift the scrolling boundary */
  584         else
  585             extra = 0;
  586         new_shift = cursor + extra + SCROLL - gl_width;
  587         if (new_shift > 0) {
  588             new_shift /= SCROLL;
  589             new_shift *= SCROLL;
  590         } else
  591             new_shift = 0;
  592         if (new_shift != gl_shift) {    /* scroll occurs */
  593             gl_shift = new_shift;
  594             off_left = (gl_shift) ? 1 : 0;
  595             off_right = (gl_cnt > gl_shift + gl_width - 1) ? 1 : 0;
  596             left = gl_shift;
  597             right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt;
  598         } else if (change >= 0) {   /* no scroll, but text changed */
  599             if (change < gl_shift + off_left)
  600                 left = gl_shift;
  601             else {
  602                 left = change;
  603                 backup = gl_pos - change;
  604             }
  605             off_right = (gl_cnt > gl_shift + gl_width - 1) ? 1 : 0;
  606             right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt;
  607         }
  608         pad -= (off_right ? gl_width - 1 : gl_cnt - gl_shift);
  609         pad = (pad < 0) ? 0 : pad;
  610         if (left <= right) {    /* clean up screen */
  611             for (i = 0; i < backup; i++)
  612                 my_fputc('\b', stdout);
  613             if (left == gl_shift && off_left) {
  614                 my_fputc('$', stdout);
  615                 left++;
  616             }
  617             for (i = left; i < right; i++) {
  618 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  619                 my_fputwc((wint_t) gl_buf[i], stdout);
  620 #else
  621                 my_fputc(gl_buf[i], stdout);
  622 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  623             }
  624             if (off_right) {
  625                 my_fputc('$', stdout);
  626                 gl_pos = right + 1;
  627             } else {
  628                 for (i = 0; i < pad; i++)   /* erase remains of prev line */
  629                     my_fputc(' ', stdout);
  630                 gl_pos = right + pad;
  631             }
  632         }
  633         i = gl_pos - cursor;    /* move to final cursor location */
  634         if (i > 0) {
  635             while (i--)
  636                 my_fputc('\b', stdout);
  637         } else {
  638             for (i = gl_pos; i < cursor; i++) {
  639 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  640                 my_fputwc((wint_t) gl_buf[i], stdout);
  641 #else
  642                 my_fputc(gl_buf[i], stdout);
  643 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  644             }
  645         }
  646         my_flush();
  647     }
  648     gl_pos = cursor;
  649 }
  650 
  651 
  652 /*
  653  * default tab handler, acts like tabstops every TAB_SIZE cols
  654  */
  655 static int
  656 gl_tab(
  657 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  658     wchar_t *wbuf,
  659 #else
  660     char *buf,
  661 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  662     int offset,
  663     int *loc)
  664 {
  665     int i, count, len;
  666 
  667 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  668     len = wcslen(wbuf);
  669     count = TAB_SIZE - (offset + *loc) % TAB_SIZE;
  670     for (i = len; i >= *loc; i--)
  671         wbuf[i + count] = wbuf[i];
  672     for (i = 0; i < count; i++)
  673         wbuf[*loc + i] = (wchar_t) ' ';
  674 #else
  675     len = strlen(buf);
  676     count = TAB_SIZE - (offset + *loc) % TAB_SIZE;
  677     for (i = len; i >= *loc; i--)
  678         buf[i + count] = buf[i];
  679     for (i = 0; i < count; i++)
  680         buf[*loc + i] = ' ';
  681 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  682     i = *loc;
  683     *loc = i + count;
  684     return i;
  685 }
  686 
  687 
  688 static void
  689 hist_add(
  690     int w)
  691 {
  692     char *p;
  693     char *tmp;
  694 
  695     if (w == HIST_NONE)
  696         return;
  697 
  698 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  699     if ((tmp = wchar_t2char(gl_buf)) == NULL)
  700         return;
  701 #else
  702     tmp = my_strdup(gl_buf);
  703 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  704 
  705     p = tmp;
  706     while (*p == ' ' || *p == '\t')     /* only save nonblank line */
  707         p++;
  708 
  709     if (*p) {
  710         input_history[w][hist_last[w]] = tmp;
  711         hist_last[w] = (hist_last[w] + 1) % HIST_SIZE;
  712         FreeAndNull(input_history[w][hist_last[w]]);    /* erase next location */
  713     } else  /* we didn't need tmp, so free it */
  714         free(tmp);
  715 
  716     hist_pos[w] = hist_last[w];
  717 }
  718 
  719 
  720 /*
  721  * loads previous hist entry into input buffer, sticks on first
  722  */
  723 static void
  724 hist_prev(
  725     int w)
  726 {
  727     int next;
  728 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  729     size_t size;
  730 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  731 
  732     if (w == HIST_NONE)
  733         return;
  734 
  735     next = (hist_pos[w] - 1 + HIST_SIZE) % HIST_SIZE;
  736     if (next != hist_last[w]) {
  737         if (input_history[w][next]) {
  738             hist_pos[w] = next;
  739 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  740             if ((size = mbstowcs(gl_buf, input_history[w][hist_pos[w]], BUF_SIZE - 1)) == (size_t) -1)
  741                 size = 0;
  742             gl_buf[size] = (wchar_t) '\0';
  743 #else
  744             strcpy(gl_buf, input_history[w][hist_pos[w]]);
  745 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  746         } else
  747             ring_bell();
  748     } else
  749         ring_bell();
  750 
  751     if (gl_in_hook)
  752         gl_in_hook(gl_buf);
  753     gl_fixup(0, BUF_SIZE);
  754 }
  755 
  756 
  757 /*
  758  * loads next hist entry into input buffer, clears on last
  759  */
  760 static void
  761 hist_next(
  762     int w)
  763 {
  764     if (w == HIST_NONE)
  765         return;
  766 
  767     if (hist_pos[w] != hist_last[w]) {
  768         hist_pos[w] = (hist_pos[w] + 1) % HIST_SIZE;
  769         if (input_history[w][hist_pos[w]]) {
  770 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  771             size_t size;
  772 
  773             if ((size = mbstowcs(gl_buf, input_history[w][hist_pos[w]], BUF_SIZE - 1)) == (size_t) -1)
  774                 size = 0;
  775             gl_buf[size] = (wchar_t) '\0';
  776 #else
  777             strcpy(gl_buf, input_history[w][hist_pos[w]]);
  778 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  779         } else
  780             gl_buf[0] = 0;
  781     } else
  782         ring_bell();
  783 
  784     if (gl_in_hook)
  785         gl_in_hook(gl_buf);
  786     gl_fixup(0, BUF_SIZE);
  787 }