"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/libedit/search.c" (4 Jul 2020, 15729 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


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 "search.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

    1 /*  $NetBSD: search.c,v 1.8 2020/07/04 13:43:21 lukem Exp $ */
    2 /*  from    NetBSD: search.c,v 1.51 2020/03/30 06:56:38 ryo Exp */
    3 
    4 /*-
    5  * Copyright (c) 1992, 1993
    6  *  The Regents of the University of California.  All rights reserved.
    7  *
    8  * This code is derived from software contributed to Berkeley by
    9  * Christos Zoulas of Cornell University.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 #include "config.h"
   37 
   38 #if 0 /* tnftp */
   39 #if !defined(lint) && !defined(SCCSID)
   40 #if 0
   41 static char sccsid[] = "@(#)search.c    8.1 (Berkeley) 6/4/93";
   42 #else
   43 __RCSID(" NetBSD: search.c,v 1.51 2020/03/30 06:56:38 ryo Exp  ");
   44 #endif
   45 #endif /* not lint && not SCCSID */
   46 #endif /* tnftp */
   47 
   48 /*
   49  * search.c: History and character search functions
   50  */
   51 #if 0 /* tnftp */
   52 #include <stdlib.h>
   53 #include <string.h>
   54 #if defined(REGEX)
   55 #include <regex.h>
   56 #elif defined(REGEXP)
   57 #include <regexp.h>
   58 #endif
   59 #endif /* tnftp */
   60 
   61 #include "el.h"
   62 #include "common.h"
   63 #include "fcns.h"
   64 
   65 /*
   66  * Adjust cursor in vi mode to include the character under it
   67  */
   68 #define EL_CURSOR(el) \
   69     ((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \
   70                 ((el)->el_map.current == (el)->el_map.alt)))
   71 
   72 /* search_init():
   73  *  Initialize the search stuff
   74  */
   75 libedit_private int
   76 search_init(EditLine *el)
   77 {
   78 
   79     el->el_search.patbuf = el_calloc(EL_BUFSIZ,
   80         sizeof(*el->el_search.patbuf));
   81     if (el->el_search.patbuf == NULL)
   82         return -1;
   83     el->el_search.patbuf[0] = L'\0';
   84     el->el_search.patlen = 0;
   85     el->el_search.patdir = -1;
   86     el->el_search.chacha = L'\0';
   87     el->el_search.chadir = CHAR_FWD;
   88     el->el_search.chatflg = 0;
   89     return 0;
   90 }
   91 
   92 
   93 /* search_end():
   94  *  Initialize the search stuff
   95  */
   96 libedit_private void
   97 search_end(EditLine *el)
   98 {
   99 
  100     el_free(el->el_search.patbuf);
  101     el->el_search.patbuf = NULL;
  102 }
  103 
  104 
  105 #ifdef REGEXP
  106 /* regerror():
  107  *  Handle regular expression errors
  108  */
  109 void
  110 /*ARGSUSED*/
  111 regerror(const char *msg)
  112 {
  113 }
  114 #endif
  115 
  116 
  117 /* el_match():
  118  *  Return if string matches pattern
  119  */
  120 libedit_private int
  121 el_match(const wchar_t *str, const wchar_t *pat)
  122 {
  123     static ct_buffer_t conv;
  124 #if defined (REGEX)
  125     regex_t re;
  126     int rv;
  127 #elif defined (REGEXP)
  128     regexp *rp;
  129     int rv;
  130 #else
  131     extern char *re_comp(const char *);
  132     extern int   re_exec(const char *);
  133 #endif
  134 
  135     if (wcsstr(str, pat) != 0)
  136         return 1;
  137 
  138 #if defined(REGEX)
  139     if (regcomp(&re, ct_encode_string(pat, &conv), 0) == 0) {
  140         rv = regexec(&re, ct_encode_string(str, &conv), (size_t)0, NULL,
  141             0) == 0;
  142         regfree(&re);
  143     } else {
  144         rv = 0;
  145     }
  146     return rv;
  147 #elif defined(REGEXP)
  148     if ((re = regcomp(ct_encode_string(pat, &conv))) != NULL) {
  149         rv = regexec(re, ct_encode_string(str, &conv));
  150         el_free(re);
  151     } else {
  152         rv = 0;
  153     }
  154     return rv;
  155 #else
  156     if (re_comp(ct_encode_string(pat, &conv)) != NULL)
  157         return 0;
  158     else
  159         return re_exec(ct_encode_string(str, &conv)) == 1;
  160 #endif
  161 }
  162 
  163 
  164 /* c_hmatch():
  165  *   return True if the pattern matches the prefix
  166  */
  167 libedit_private int
  168 c_hmatch(EditLine *el, const wchar_t *str)
  169 {
  170 #ifdef SDEBUG
  171     (void) fprintf(el->el_errfile, "match `%ls' with `%ls'\n",
  172         el->el_search.patbuf, str);
  173 #endif /* SDEBUG */
  174 
  175     return el_match(str, el->el_search.patbuf);
  176 }
  177 
  178 
  179 /* c_setpat():
  180  *  Set the history seatch pattern
  181  */
  182 libedit_private void
  183 c_setpat(EditLine *el)
  184 {
  185     if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY &&
  186         el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) {
  187         el->el_search.patlen =
  188             (size_t)(EL_CURSOR(el) - el->el_line.buffer);
  189         if (el->el_search.patlen >= EL_BUFSIZ)
  190             el->el_search.patlen = EL_BUFSIZ - 1;
  191         (void) wcsncpy(el->el_search.patbuf, el->el_line.buffer,
  192             el->el_search.patlen);
  193         el->el_search.patbuf[el->el_search.patlen] = '\0';
  194     }
  195 #ifdef SDEBUG
  196     (void) fprintf(el->el_errfile, "\neventno = %d\n",
  197         el->el_history.eventno);
  198     (void) fprintf(el->el_errfile, "patlen = %ld\n", el->el_search.patlen);
  199     (void) fprintf(el->el_errfile, "patbuf = \"%ls\"\n",
  200         el->el_search.patbuf);
  201     (void) fprintf(el->el_errfile, "cursor %ld lastchar %ld\n",
  202         EL_CURSOR(el) - el->el_line.buffer,
  203         el->el_line.lastchar - el->el_line.buffer);
  204 #endif
  205 }
  206 
  207 
  208 /* ce_inc_search():
  209  *  Emacs incremental search
  210  */
  211 libedit_private el_action_t
  212 ce_inc_search(EditLine *el, int dir)
  213 {
  214     static const wchar_t STRfwd[] = L"fwd", STRbck[] = L"bck";
  215     static wchar_t pchar = L':';  /* ':' = normal, '?' = failed */
  216     static wchar_t endcmd[2] = {'\0', '\0'};
  217     wchar_t *ocursor = el->el_line.cursor, oldpchar = pchar, ch;
  218     const wchar_t *cp;
  219 
  220     el_action_t ret = CC_NORM;
  221 
  222     int ohisteventno = el->el_history.eventno;
  223     size_t oldpatlen = el->el_search.patlen;
  224     int newdir = dir;
  225     int done, redo;
  226 
  227     if (el->el_line.lastchar + sizeof(STRfwd) /
  228         sizeof(*el->el_line.lastchar) + 2 +
  229         el->el_search.patlen >= el->el_line.limit)
  230         return CC_ERROR;
  231 
  232     for (;;) {
  233 
  234         if (el->el_search.patlen == 0) {    /* first round */
  235             pchar = ':';
  236 #ifdef ANCHOR
  237 #define LEN 2
  238             el->el_search.patbuf[el->el_search.patlen++] = '.';
  239             el->el_search.patbuf[el->el_search.patlen++] = '*';
  240 #else
  241 #define LEN 0
  242 #endif
  243         }
  244         done = redo = 0;
  245         *el->el_line.lastchar++ = '\n';
  246         for (cp = (newdir == ED_SEARCH_PREV_HISTORY) ? STRbck : STRfwd;
  247             *cp; *el->el_line.lastchar++ = *cp++)
  248             continue;
  249         *el->el_line.lastchar++ = pchar;
  250         for (cp = &el->el_search.patbuf[LEN];
  251             cp < &el->el_search.patbuf[el->el_search.patlen];
  252             *el->el_line.lastchar++ = *cp++)
  253             continue;
  254         *el->el_line.lastchar = '\0';
  255         re_refresh(el);
  256 
  257         if (el_wgetc(el, &ch) != 1)
  258             return ed_end_of_file(el, 0);
  259 
  260         switch (el->el_map.current[(unsigned char) ch]) {
  261         case ED_INSERT:
  262         case ED_DIGIT:
  263             if (el->el_search.patlen >= EL_BUFSIZ - LEN)
  264                 terminal_beep(el);
  265             else {
  266                 el->el_search.patbuf[el->el_search.patlen++] =
  267                     ch;
  268                 *el->el_line.lastchar++ = ch;
  269                 *el->el_line.lastchar = '\0';
  270                 re_refresh(el);
  271             }
  272             break;
  273 
  274         case EM_INC_SEARCH_NEXT:
  275             newdir = ED_SEARCH_NEXT_HISTORY;
  276             redo++;
  277             break;
  278 
  279         case EM_INC_SEARCH_PREV:
  280             newdir = ED_SEARCH_PREV_HISTORY;
  281             redo++;
  282             break;
  283 
  284         case EM_DELETE_PREV_CHAR:
  285         case ED_DELETE_PREV_CHAR:
  286             if (el->el_search.patlen > LEN)
  287                 done++;
  288             else
  289                 terminal_beep(el);
  290             break;
  291 
  292         default:
  293             switch (ch) {
  294             case 0007:  /* ^G: Abort */
  295                 ret = CC_ERROR;
  296                 done++;
  297                 break;
  298 
  299             case 0027:  /* ^W: Append word */
  300             /* No can do if globbing characters in pattern */
  301                 for (cp = &el->el_search.patbuf[LEN];; cp++)
  302                     if (cp >= &el->el_search.patbuf[
  303                     el->el_search.patlen]) {
  304                     el->el_line.cursor +=
  305                         el->el_search.patlen - LEN - 1;
  306                     cp = c__next_word(el->el_line.cursor,
  307                         el->el_line.lastchar, 1,
  308                         ce__isword);
  309                     while (el->el_line.cursor < cp &&
  310                         *el->el_line.cursor != '\n') {
  311                         if (el->el_search.patlen >=
  312                             EL_BUFSIZ - LEN) {
  313                             terminal_beep(el);
  314                             break;
  315                         }
  316                         el->el_search.patbuf[el->el_search.patlen++] =
  317                             *el->el_line.cursor;
  318                         *el->el_line.lastchar++ =
  319                             *el->el_line.cursor++;
  320                     }
  321                     el->el_line.cursor = ocursor;
  322                     *el->el_line.lastchar = '\0';
  323                     re_refresh(el);
  324                     break;
  325                     } else if (isglob(*cp)) {
  326                         terminal_beep(el);
  327                         break;
  328                     }
  329                 break;
  330 
  331             default:    /* Terminate and execute cmd */
  332                 endcmd[0] = ch;
  333                 el_wpush(el, endcmd);
  334                 /* FALLTHROUGH */
  335 
  336             case 0033:  /* ESC: Terminate */
  337                 ret = CC_REFRESH;
  338                 done++;
  339                 break;
  340             }
  341             break;
  342         }
  343 
  344         while (el->el_line.lastchar > el->el_line.buffer &&
  345             *el->el_line.lastchar != '\n')
  346             *el->el_line.lastchar-- = '\0';
  347         *el->el_line.lastchar = '\0';
  348 
  349         if (!done) {
  350 
  351             /* Can't search if unmatched '[' */
  352             for (cp = &el->el_search.patbuf[el->el_search.patlen-1],
  353                 ch = L']';
  354                 cp >= &el->el_search.patbuf[LEN];
  355                 cp--)
  356                 if (*cp == '[' || *cp == ']') {
  357                     ch = *cp;
  358                     break;
  359                 }
  360             if (el->el_search.patlen > LEN && ch != L'[') {
  361                 if (redo && newdir == dir) {
  362                     if (pchar == '?') { /* wrap around */
  363                         el->el_history.eventno =
  364                             newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff;
  365                         if (hist_get(el) == CC_ERROR)
  366                             /* el->el_history.event
  367                              * no was fixed by
  368                              * first call */
  369                             (void) hist_get(el);
  370                         el->el_line.cursor = newdir ==
  371                             ED_SEARCH_PREV_HISTORY ?
  372                             el->el_line.lastchar :
  373                             el->el_line.buffer;
  374                     } else
  375                         el->el_line.cursor +=
  376                             newdir ==
  377                             ED_SEARCH_PREV_HISTORY ?
  378                             -1 : 1;
  379                 }
  380 #ifdef ANCHOR
  381                 el->el_search.patbuf[el->el_search.patlen++] =
  382                     '.';
  383                 el->el_search.patbuf[el->el_search.patlen++] =
  384                     '*';
  385 #endif
  386                 el->el_search.patbuf[el->el_search.patlen] =
  387                     '\0';
  388                 if (el->el_line.cursor < el->el_line.buffer ||
  389                     el->el_line.cursor > el->el_line.lastchar ||
  390                     (ret = ce_search_line(el, newdir))
  391                     == CC_ERROR) {
  392                     /* avoid c_setpat */
  393                     el->el_state.lastcmd =
  394                         (el_action_t) newdir;
  395                     ret = (el_action_t)
  396                         (newdir == ED_SEARCH_PREV_HISTORY ?
  397                         ed_search_prev_history(el, 0) :
  398                         ed_search_next_history(el, 0));
  399                     if (ret != CC_ERROR) {
  400                         el->el_line.cursor = newdir ==
  401                             ED_SEARCH_PREV_HISTORY ?
  402                             el->el_line.lastchar :
  403                             el->el_line.buffer;
  404                         (void) ce_search_line(el,
  405                             newdir);
  406                     }
  407                 }
  408                 el->el_search.patlen -= LEN;
  409                 el->el_search.patbuf[el->el_search.patlen] =
  410                     '\0';
  411                 if (ret == CC_ERROR) {
  412                     terminal_beep(el);
  413                     if (el->el_history.eventno !=
  414                         ohisteventno) {
  415                         el->el_history.eventno =
  416                             ohisteventno;
  417                         if (hist_get(el) == CC_ERROR)
  418                             return CC_ERROR;
  419                     }
  420                     el->el_line.cursor = ocursor;
  421                     pchar = '?';
  422                 } else {
  423                     pchar = ':';
  424                 }
  425             }
  426             ret = ce_inc_search(el, newdir);
  427 
  428             if (ret == CC_ERROR && pchar == '?' && oldpchar == ':')
  429                 /*
  430                  * break abort of failed search at last
  431                  * non-failed
  432                  */
  433                 ret = CC_NORM;
  434 
  435         }
  436         if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
  437             /* restore on normal return or error exit */
  438             pchar = oldpchar;
  439             el->el_search.patlen = oldpatlen;
  440             if (el->el_history.eventno != ohisteventno) {
  441                 el->el_history.eventno = ohisteventno;
  442                 if (hist_get(el) == CC_ERROR)
  443                     return CC_ERROR;
  444             }
  445             el->el_line.cursor = ocursor;
  446             if (ret == CC_ERROR)
  447                 re_refresh(el);
  448         }
  449         if (done || ret != CC_NORM)
  450             return ret;
  451     }
  452 }
  453 
  454 
  455 /* cv_search():
  456  *  Vi search.
  457  */
  458 libedit_private el_action_t
  459 cv_search(EditLine *el, int dir)
  460 {
  461     wchar_t ch;
  462     wchar_t tmpbuf[EL_BUFSIZ];
  463     ssize_t tmplen;
  464 
  465 #ifdef ANCHOR
  466     tmpbuf[0] = '.';
  467     tmpbuf[1] = '*';
  468 #endif
  469     tmplen = LEN;
  470 
  471     el->el_search.patdir = dir;
  472 
  473     tmplen = c_gets(el, &tmpbuf[LEN],
  474         dir == ED_SEARCH_PREV_HISTORY ? L"\n/" : L"\n?" );
  475     if (tmplen == -1)
  476         return CC_REFRESH;
  477 
  478     tmplen += LEN;
  479     ch = tmpbuf[tmplen];
  480     tmpbuf[tmplen] = '\0';
  481 
  482     if (tmplen == LEN) {
  483         /*
  484          * Use the old pattern, but wild-card it.
  485          */
  486         if (el->el_search.patlen == 0) {
  487             re_refresh(el);
  488             return CC_ERROR;
  489         }
  490 #ifdef ANCHOR
  491         if (el->el_search.patbuf[0] != '.' &&
  492             el->el_search.patbuf[0] != '*') {
  493             (void) wcsncpy(tmpbuf, el->el_search.patbuf,
  494                 sizeof(tmpbuf) / sizeof(*tmpbuf) - 1);
  495             el->el_search.patbuf[0] = '.';
  496             el->el_search.patbuf[1] = '*';
  497             (void) wcsncpy(&el->el_search.patbuf[2], tmpbuf,
  498                 EL_BUFSIZ - 3);
  499             el->el_search.patlen++;
  500             el->el_search.patbuf[el->el_search.patlen++] = '.';
  501             el->el_search.patbuf[el->el_search.patlen++] = '*';
  502             el->el_search.patbuf[el->el_search.patlen] = '\0';
  503         }
  504 #endif
  505     } else {
  506 #ifdef ANCHOR
  507         tmpbuf[tmplen++] = '.';
  508         tmpbuf[tmplen++] = '*';
  509 #endif
  510         tmpbuf[tmplen] = '\0';
  511         (void) wcsncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1);
  512         el->el_search.patlen = (size_t)tmplen;
  513     }
  514     el->el_state.lastcmd = (el_action_t) dir;   /* avoid c_setpat */
  515     el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer;
  516     if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) :
  517         ed_search_next_history(el, 0)) == CC_ERROR) {
  518         re_refresh(el);
  519         return CC_ERROR;
  520     }
  521     if (ch == 0033) {
  522         re_refresh(el);
  523         return ed_newline(el, 0);
  524     }
  525     return CC_REFRESH;
  526 }
  527 
  528 
  529 /* ce_search_line():
  530  *  Look for a pattern inside a line
  531  */
  532 libedit_private el_action_t
  533 ce_search_line(EditLine *el, int dir)
  534 {
  535     wchar_t *cp = el->el_line.cursor;
  536     wchar_t *pattern = el->el_search.patbuf;
  537     wchar_t oc, *ocp;
  538 #ifdef ANCHOR
  539     ocp = &pattern[1];
  540     oc = *ocp;
  541     *ocp = '^';
  542 #else
  543     ocp = pattern;
  544     oc = *ocp;
  545 #endif
  546 
  547     if (dir == ED_SEARCH_PREV_HISTORY) {
  548         for (; cp >= el->el_line.buffer; cp--) {
  549             if (el_match(cp, ocp)) {
  550                 *ocp = oc;
  551                 el->el_line.cursor = cp;
  552                 return CC_NORM;
  553             }
  554         }
  555         *ocp = oc;
  556         return CC_ERROR;
  557     } else {
  558         for (; *cp != '\0' && cp < el->el_line.limit; cp++) {
  559             if (el_match(cp, ocp)) {
  560                 *ocp = oc;
  561                 el->el_line.cursor = cp;
  562                 return CC_NORM;
  563             }
  564         }
  565         *ocp = oc;
  566         return CC_ERROR;
  567     }
  568 }
  569 
  570 
  571 /* cv_repeat_srch():
  572  *  Vi repeat search
  573  */
  574 libedit_private el_action_t
  575 cv_repeat_srch(EditLine *el, wint_t c)
  576 {
  577 
  578 #ifdef SDEBUG
  579     static ct_buffer_t conv;
  580     (void) fprintf(el->el_errfile, "dir %d patlen %ld patbuf %s\n",
  581         c, el->el_search.patlen, ct_encode_string(el->el_search.patbuf, &conv));
  582 #endif
  583 
  584     el->el_state.lastcmd = (el_action_t) c; /* Hack to stop c_setpat */
  585     el->el_line.lastchar = el->el_line.buffer;
  586 
  587     switch (c) {
  588     case ED_SEARCH_NEXT_HISTORY:
  589         return ed_search_next_history(el, 0);
  590     case ED_SEARCH_PREV_HISTORY:
  591         return ed_search_prev_history(el, 0);
  592     default:
  593         return CC_ERROR;
  594     }
  595 }
  596 
  597 
  598 /* cv_csearch():
  599  *  Vi character search
  600  */
  601 libedit_private el_action_t
  602 cv_csearch(EditLine *el, int direction, wint_t ch, int count, int tflag)
  603 {
  604     wchar_t *cp;
  605 
  606     if (ch == 0)
  607         return CC_ERROR;
  608 
  609     if (ch == (wint_t)-1) {
  610         wchar_t c;
  611         if (el_wgetc(el, &c) != 1)
  612             return ed_end_of_file(el, 0);
  613         ch = c;
  614     }
  615 
  616     /* Save for ';' and ',' commands */
  617     el->el_search.chacha = ch;
  618     el->el_search.chadir = direction;
  619     el->el_search.chatflg = (char)tflag;
  620 
  621     cp = el->el_line.cursor;
  622     while (count--) {
  623         if ((wint_t)*cp == ch)
  624             cp += direction;
  625         for (;;cp += direction) {
  626             if (cp >= el->el_line.lastchar)
  627                 return CC_ERROR;
  628             if (cp < el->el_line.buffer)
  629                 return CC_ERROR;
  630             if ((wint_t)*cp == ch)
  631                 break;
  632         }
  633     }
  634 
  635     if (tflag)
  636         cp -= direction;
  637 
  638     el->el_line.cursor = cp;
  639 
  640     if (el->el_chared.c_vcmd.action != NOP) {
  641         if (direction > 0)
  642             el->el_line.cursor++;
  643         cv_delfini(el);
  644         return CC_REFRESH;
  645     }
  646     return CC_CURSOR;
  647 }