"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.1/src/prompt.c" (12 Oct 2016, 18910 Bytes) of archive /linux/misc/tin-2.4.1.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 "prompt.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.0_vs_2.4.1.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : prompt.c
    4  *  Author    : I. Lea
    5  *  Created   : 1991-04-01
    6  *  Updated   : 2015-10-31
    7  *  Notes     :
    8  *
    9  * Copyright (c) 1991-2017 Iain Lea <iain@bricbrac.de>
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. The name of the author may not be used to endorse or promote
   21  *    products derived from this software without specific prior written
   22  *    permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   25  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   28  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   30  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  */
   36 
   37 
   38 #ifndef TIN_H
   39 #   include "tin.h"
   40 #endif /* !TIN_H */
   41 #ifndef TCURSES_H
   42 #   include "tcurses.h"
   43 #endif /* !TCURSES_H */
   44 
   45 
   46 static char *prompt_slk_message;    /* prompt message for prompt_slk_redraw */
   47 static char *prompt_yn_message;
   48 static char *prompt_yn_choice;
   49 
   50 /*
   51  * Local prototypes
   52  */
   53 static int prompt_list(int row, int col, int var, constext *help_text, constext *prompt_text, constext *list[], int size);
   54 
   55 
   56 /*
   57  *  prompt_num
   58  *  get a number from the user
   59  *  Return -1 if missing or bad number typed
   60  */
   61 int
   62 prompt_num(
   63     int ch,
   64     const char *prompt)
   65 {
   66     char *p;
   67     char tmp[LEN];
   68     int num;
   69 
   70     clear_message();
   71     snprintf(tmp, sizeof(tmp), "%c", ch);
   72     if ((p = tin_getline(prompt, TRUE, tmp, 0, FALSE, HIST_OTHER)) != NULL) {
   73         STRCPY(tmp, p);
   74         num = atoi(tmp);
   75     } else
   76         num = -1;
   77 
   78     clear_message();
   79     return num;
   80 }
   81 
   82 
   83 /*
   84  *  prompt_string
   85  *  get a string from the user
   86  *  Return TRUE if a valid string was typed, FALSE otherwise
   87  *  TODO: no bounds checking on buf size, tin_getline() defaults to 1024
   88  */
   89 t_bool
   90 prompt_string(
   91     const char *prompt,
   92     char *buf,
   93     int which_hist)
   94 {
   95     return prompt_default_string(prompt, buf, 0, (char *) NULL, which_hist);
   96 }
   97 
   98 
   99 /*
  100  * prompt_default_string
  101  * get a string from the user, display default value
  102  * Return TRUE if a valid string was typed, FALSE otherwise
  103  */
  104 t_bool
  105 prompt_default_string(
  106     const char *prompt,
  107     char *buf,
  108     int buf_len,
  109     char *default_prompt,
  110     int which_hist)
  111 {
  112     char *p;
  113 
  114     clear_message();
  115     if ((p = tin_getline(prompt, FALSE, default_prompt, buf_len, FALSE, which_hist)) == NULL) {
  116         buf[0] = '\0';
  117         clear_message();
  118         return FALSE;
  119     }
  120     strcpy(buf, p);
  121     clear_message();
  122     return TRUE;
  123 }
  124 
  125 
  126 /*
  127  *  prompt_menu_string
  128  *  get a string from the user
  129  *  Return TRUE if a valid string was typed, FALSE otherwise
  130  */
  131 t_bool
  132 prompt_menu_string(
  133     int line,
  134     const char *prompt,
  135     char *var)
  136 {
  137     char *p;
  138 
  139     /*
  140      * clear buffer - this is needed, otherwise a lost
  141      * connection right before a resync_active() call
  142      * would lead to a 'n' answer to the reconnect prompt
  143      */
  144     /* fflush(stdin); */
  145     MoveCursor(line, 0);
  146     if ((p = tin_getline(prompt, FALSE, var, 0, FALSE, HIST_OTHER)) == NULL)
  147         return FALSE;
  148 
  149     strcpy(var, p);
  150     return TRUE;
  151 }
  152 
  153 
  154 /*
  155  * prompt_yn
  156  * prompt user for 'y'es or 'n'o decision. "prompt" will be displayed in the
  157  * last line giving the default answer "default_answer".
  158  * The function returns 1 if the user decided "yes", -1 if the user wanted
  159  * to escape, or 0 for any other decision.
  160  */
  161 int
  162 prompt_yn(
  163     const char *prompt,
  164     t_bool default_answer)
  165 {
  166     char *keyprompt;
  167     char keyno[MAXKEYLEN], keyyes[MAXKEYLEN];
  168     int keyyes_len, keyno_len, maxlen, prompt_len;
  169     t_function func;
  170 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  171     wint_t yes, no, prompt_ch, ch;
  172 #else
  173     char yes, no, prompt_ch;
  174     int ch;
  175 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  176 
  177 /*  fflush(stdin); */       /* Prevent finger trouble from making important decisions */
  178 
  179     yes = func_to_key(PROMPT_YES, prompt_keys);
  180     no = func_to_key(PROMPT_NO, prompt_keys);
  181 
  182 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  183     printascii(keyyes, (default_answer ? towupper(yes) : yes));
  184     printascii(keyno, (!default_answer ? towupper(no) : no));
  185 #else
  186     printascii(keyyes, (default_answer ? toupper(yes) : yes));
  187     printascii(keyno, (!default_answer ? toupper(no) : no));
  188 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  189     keyyes_len = strwidth(keyyes);
  190     keyno_len = strwidth(keyno);
  191     maxlen = MAX(keyyes_len, keyno_len);
  192     prompt_len = keyyes_len + keyno_len + maxlen + 6;
  193     prompt_yn_message = my_strdup(prompt);
  194     prompt_yn_choice = my_malloc(prompt_len + 1);
  195 
  196     input_context = cPromptYN;
  197 
  198     do {
  199         prompt_ch = (default_answer ? yes : no);
  200         keyprompt = (default_answer ? keyyes : keyno);
  201 
  202         snprintf(prompt_yn_choice, prompt_len, " (%s/%s) %-*s", keyyes, keyno, maxlen, keyprompt);
  203         prompt_yn_redraw();
  204 
  205 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  206         if (((ch = ReadWch()) == '\n') || (ch == '\r'))
  207 #else
  208         if (((ch = (char) ReadCh()) == '\n') || (ch == '\r'))
  209 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  210             ch = prompt_ch;
  211 
  212         switch (ch) {
  213             case ESC:   /* (ESC) common arrow keys */
  214 #   ifdef HAVE_KEY_PREFIX
  215             case KEY_PREFIX:
  216 #   endif /* HAVE_KEY_PREFIX */
  217                 switch (get_arrow_key((int) ch)) {
  218                     case KEYMAP_UP:
  219                     case KEYMAP_DOWN:
  220                         default_answer = bool_not(default_answer);
  221                         ch = '\0';  /* set to a not bindable key to not leave the loop yet */
  222                         break;
  223 
  224                     case KEYMAP_LEFT:
  225                         ch = ESC;
  226                         break;
  227 
  228                     case KEYMAP_RIGHT:
  229                         ch = prompt_ch;
  230                         break;
  231 
  232                     default:
  233                         break;
  234                 }
  235                 break;
  236 
  237             default:
  238                 break;
  239         }
  240         func = key_to_func(ch, prompt_keys);
  241     } while (func == NOT_ASSIGNED);
  242 
  243     input_context = cNone;
  244     FreeAndNull(prompt_yn_message);
  245     FreeAndNull(prompt_yn_choice);
  246 
  247     if (!cmd_line) {
  248         clear_message();
  249         my_flush();
  250     }
  251     return (func == PROMPT_YES) ? 1 : (func == GLOBAL_ABORT) ? -1 : 0;
  252 }
  253 
  254 
  255 /*
  256  * (Re)draws and resize the prompt message for prompt_yn()
  257  */
  258 void
  259 prompt_yn_redraw(
  260     void)
  261 {
  262     char *buf;
  263     int choice_len = strwidth(prompt_yn_choice);
  264     int message_len = strwidth(prompt_yn_message);
  265 
  266     if (!cmd_line) {
  267         MoveCursor(cLINES, 0);
  268         CleartoEOLN();
  269     }
  270     if (message_len + choice_len > cCOLS - 1) {
  271         buf = strunc(prompt_yn_message, cCOLS - choice_len - 1);
  272         message_len = strwidth(buf);
  273         my_printf("%s%s", buf, prompt_yn_choice);
  274         free(buf);
  275     } else
  276         my_printf("%s%s", prompt_yn_message, prompt_yn_choice);
  277 
  278     if (!cmd_line)
  279         cursoron();
  280     my_flush();
  281     if (!cmd_line)
  282         MoveCursor(cLINES, (message_len + choice_len) - 1);
  283 }
  284 
  285 
  286 /*
  287  * help_text is displayed near the bottom of the screen.
  288  * var is an index into a list containing size elements.
  289  * The text from list is shown at row, col + len(prompt_text)
  290  * Choice is incremented using the space bar, wrapping to 0
  291  * ESC is used to abort any changes, RET saves changes.
  292  * The new value is returned.
  293  */
  294 static int
  295 prompt_list(
  296     int row,
  297     int col,
  298     int var,
  299     constext *help_text,
  300     constext *prompt_text,
  301     constext *list[],
  302     int size)
  303 {
  304     int ch, var_orig;
  305     int i, offset, width = 0;
  306     int change;
  307     int adjust = (strcasecmp(_(list[0]), _(txt_default)) == 0);
  308 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  309     char *buf;
  310 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  311 
  312     var += adjust;
  313     var_orig = var;
  314 
  315     /*
  316      * Find the length of longest printable text
  317      */
  318     for (i = 0; i < size; i++)
  319         width = MAX(width, strwidth(_(list[i])));
  320 
  321     show_menu_help(help_text);
  322     cursoron();
  323 
  324     offset = strwidth(_(prompt_text));
  325 
  326     /*
  327      * Make sure to not exceed cCOLS
  328      */
  329     if (offset + width >= cCOLS)
  330         width = cCOLS - offset - 1;
  331 
  332     do {
  333         MoveCursor(row, col + offset);
  334         ch = (char) ReadCh();
  335 
  336         /*
  337          * change:
  338          *   1 = move to the next list element
  339          *   0 = do nothing
  340          *  -1 = move to the previous list element
  341          *
  342          *  if an arrow key was pressed change ch to another value
  343          *  otherwise we will exit the while loop
  344          */
  345         switch (ch) {
  346             case ' ':
  347                 change = 1;
  348                 break;
  349 
  350             case ESC:   /* (ESC) common arrow keys */
  351 #   ifdef HAVE_KEY_PREFIX
  352             case KEY_PREFIX:
  353 #   endif /* HAVE_KEY_PREFIX */
  354                 switch (get_arrow_key(ch)) {
  355                     case KEYMAP_UP:
  356                         change = -1;
  357                         ch = ' ';
  358                         break;
  359 
  360                     case KEYMAP_DOWN:
  361                         change = 1;
  362                         ch = ' ';
  363                         break;
  364 
  365                     default:
  366                         change = 0;
  367                         break;
  368                 }
  369                 break;
  370 
  371             default:
  372                 change = 0;
  373                 break;
  374         }
  375 
  376         if (change) {
  377             /*
  378              * increment or decrement list, loop around at the limits
  379              */
  380             var += change;
  381             if (var < 0)
  382                 var = size - 1;
  383             else
  384                 var %= (size ? size : 1);
  385 
  386 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  387             if ((buf = spart(_(list[var]), width, TRUE)) != NULL) {
  388                 my_printf("%s", buf);
  389                 free(buf);
  390             } else
  391 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  392                 my_printf("%-*s", width, _(list[var]));
  393             my_flush();
  394         }
  395     } while (ch != '\r' && ch != '\n' && ch != ESC);
  396 
  397     if (ch == ESC) {
  398         var = var_orig;
  399 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  400         if ((buf = spart(_(list[var]), width, TRUE)) != NULL) {
  401             my_printf("%s", buf);
  402             free(buf);
  403         } else
  404 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  405             my_printf("%-*s", width, _(list[var]));
  406         my_flush();
  407     }
  408 
  409     cursoroff();
  410     return (var - adjust);
  411 }
  412 
  413 
  414 /*
  415  * Special case of prompt_option_list() Toggle between ON and OFF
  416  * The function returns TRUE, if the value was changed, FALSE otherwise.
  417  */
  418 t_bool
  419 prompt_option_on_off(
  420     enum option_enum option)
  421 {
  422     char prompt[LEN];
  423     t_bool *variable = OPT_ON_OFF_list[option_table[option].var_index];
  424     t_bool old_value = *variable;
  425 
  426     fmt_option_prompt(prompt, sizeof(prompt), TRUE, option);
  427     *variable = prompt_list(option_row(option), 0, *variable, option_table[option].txt->help, prompt, txt_onoff, 2) ? TRUE : FALSE;
  428     return bool_not(bool_equal(*variable, old_value));
  429 }
  430 
  431 
  432 /*
  433  * The function returns TRUE, if the value was changed, FALSE otherwise.
  434  */
  435 t_bool
  436 prompt_option_list(
  437     enum option_enum option)
  438 {
  439     char prompt[LEN];
  440     int *variable = option_table[option].variable;
  441     int old_value = *variable;
  442     int opt_count = 0;
  443 
  444     while (option_table[option].opt_list[opt_count] != NULL)
  445         ++opt_count;
  446     fmt_option_prompt(prompt, sizeof(prompt), TRUE, option);
  447     *variable = prompt_list(option_row(option), 0, *variable, option_table[option].txt->help, prompt, option_table[option].opt_list, opt_count);
  448     return *variable != old_value;
  449 }
  450 
  451 
  452 /*
  453  * Displays option text and actual option value for string based options in
  454  * one line, help text for that option near the bottom of the screen. Allows
  455  * change of the old value by normal editing; history function of tin_getline()
  456  * will be used properly so that editing won't leave the actual line.
  457  *
  458  * The function returns TRUE, if the value was changed, FALSE otherwise.
  459  */
  460 t_bool
  461 prompt_option_string(
  462     enum option_enum option) /* return value is always ignored */
  463 {
  464     char *variable = OPT_STRING_list[option_table[option].var_index];
  465     char prompt[LEN];
  466     char old_value[LEN];
  467 
  468     STRCPY(old_value, variable);
  469     show_menu_help(option_table[option].txt->help);
  470     fmt_option_prompt(prompt, sizeof(prompt) - 1, TRUE, option);
  471     if (prompt_menu_string(option_row(option), prompt, variable))
  472         return strcmp(old_value, variable) ? TRUE : FALSE;
  473     else
  474         return FALSE;
  475 }
  476 
  477 
  478 /*
  479  * Displays option text and current option value for number based options in
  480  * one line, help text for that option near the bottom of the screen. Allows
  481  * change of the old value by normal editing; history function of tin_getline()
  482  * will be used properly so that editing won't leave the current line.
  483  *
  484  * The function returns TRUE if the value was changed, FALSE otherwise.
  485  */
  486 t_bool
  487 prompt_option_num(
  488     enum option_enum option) /* return value is always ignored */
  489 {
  490     char prompt[LEN];
  491     char number[LEN];
  492     char *p;
  493     int num;
  494 
  495     show_menu_help(option_table[option].txt->help);
  496     MoveCursor(option_row(option), 0);
  497     fmt_option_prompt(prompt, sizeof(prompt) - 1, TRUE, option);
  498     snprintf(&number[0], sizeof(number), "%d", *(option_table[option].variable));
  499 
  500     if ((p = tin_getline(prompt, 2, number, 0, FALSE, HIST_OTHER)) == NULL)
  501         return FALSE;
  502 
  503     STRCPY(number, p);
  504     num = atoi(number);
  505     *(option_table[option].variable) = num;
  506     clear_message();
  507     return TRUE;
  508 }
  509 
  510 
  511 /*
  512  * Displays option text and actual option value for character based options
  513  * in one line, help text for that option near the bottom of the screen.
  514  * Allows change of the old value by normal editing.
  515  *
  516  * The function returns TRUE if the value was changed, FALSE otherwise.
  517  */
  518 t_bool
  519 prompt_option_char(
  520     enum option_enum option) /* return value is always ignored */
  521 {
  522     char prompt[LEN];
  523     char input[2];
  524     char *p = &input[0];
  525     char *variable = OPT_CHAR_list[option_table[option].var_index];
  526 
  527     input[0] = *variable;
  528     input[1] = '\0';
  529 
  530     do {
  531         show_menu_help(option_table[option].txt->help);
  532         MoveCursor(option_row(option), 0);
  533         fmt_option_prompt(prompt, sizeof(prompt) - 1, TRUE, option);
  534 
  535         if ((p = tin_getline(prompt, FALSE, p, 1, FALSE, HIST_OTHER)) == NULL) {
  536             clear_message();
  537             return FALSE;
  538         }
  539         if (!*p)
  540             info_message(_(txt_info_enter_valid_character));
  541     } while (!*p);
  542 
  543     *variable = p[0];
  544     clear_message();
  545     return TRUE;
  546 }
  547 
  548 
  549 /*
  550  * Get a string. Make it the new default.
  551  * If none given, use the default.
  552  * Return the string or NULL if we can't get anything useful
  553  */
  554 char *
  555 prompt_string_default(
  556     const char *prompt,
  557     char *def,
  558     const char *failtext,
  559     int history)
  560 {
  561     char pattern[LEN];
  562 
  563     clear_message();
  564 
  565     if (!prompt_string(prompt, pattern, history)) {
  566         clear_message();
  567         return NULL;
  568     }
  569 
  570     if (pattern[0] != '\0')         /* got a string - make it the default */
  571         my_strncpy(def, pattern, LEN);
  572     else {
  573         if (def[0] == '\0') {       /* no default - give up */
  574             error_message(2, "%s", failtext);
  575             return NULL;
  576         }
  577     }
  578 
  579     return def;                 /* use the default */
  580 }
  581 
  582 
  583 /*
  584  * Get a message ID for the 'L' command. Add <> if needed
  585  * If the msgid exists and is reachable, return its index
  586  * in arts[], else ART_UNAVAILABLE
  587  */
  588 int
  589 prompt_msgid(
  590     void)
  591 {
  592     char buf[LEN];
  593 
  594     if (prompt_string(_(txt_enter_message_id), buf + 1, HIST_MESSAGE_ID) && buf[1]) {
  595         char *ptr = str_trim(buf + 1);
  596         struct t_msgid *msgid;
  597 
  598         /*
  599          * If the user failed to supply Message-ID in <>, add them
  600          */
  601         if (buf[1] != '<') {
  602             buf[0] = '<';
  603             strcat(buf, ">");
  604             ptr = buf;
  605         }
  606 
  607         if ((msgid = find_msgid(ptr)) == NULL) {
  608             info_message(_(txt_art_unavailable));
  609             return ART_UNAVAILABLE;
  610         }
  611 
  612         /*
  613          * Is it expired or otherwise not on the spool ?
  614          */
  615         if (msgid->article == ART_UNAVAILABLE) {
  616             info_message(_(txt_art_unavailable));
  617             return ART_UNAVAILABLE;
  618         }
  619 
  620         /*
  621          * If the article is no longer part of a thread, then there is
  622          * no way to display it
  623          */
  624         if (which_thread(msgid->article) == -1) {
  625             info_message(_(txt_no_last_message));
  626             return ART_UNAVAILABLE;
  627         }
  628 
  629         return msgid->article;
  630     }
  631 
  632     return ART_UNAVAILABLE;
  633 }
  634 
  635 
  636 /*
  637  * Format a message such that it'll fit within the screen width
  638  * Useful for fitting long Subjects and newsgroup names into prompts
  639  * result will contain a pointer to the malloced memory containing the
  640  * sized message
  641  */
  642 char *
  643 sized_message(
  644     char **result,
  645     const char *format,
  646     const char *subject)
  647 {
  648     char *buf;
  649     int max_len;
  650 
  651     max_len = cCOLS - strwidth(format) + 2 - 1; /* The formatting info (%s) wastes 2 chars, but our prompt needs 1 char */
  652 
  653     buf = strunc(subject, max_len);
  654 
  655     *result = fmt_string(format, buf);
  656     free(buf);
  657 
  658     return *result;
  659 }
  660 
  661 
  662 /*
  663  * Implement the Single-Letter-Key mini menus at the bottom of the screen
  664  * eg, Press a)ppend, o)verwrite, q)uit :
  665  */
  666 t_function
  667 prompt_slk_response(
  668     t_function default_func,
  669     const struct keylist keys,
  670     const char *fmt,
  671     ...)
  672 {
  673     va_list ap;
  674     char buf[LEN];
  675     t_function func;
  676 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  677     wchar_t ch;
  678 #else
  679     char ch;
  680 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  681 
  682     va_start(ap, fmt);
  683     vsnprintf(buf, sizeof(buf), fmt, ap);
  684     va_end(ap);
  685 
  686     prompt_slk_message = my_malloc(strlen(buf) + 2);
  687 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  688     {
  689         char *tmp;
  690         wchar_t wtmp[2] = { '\0', '\0' };
  691 
  692         wtmp[0] = func_to_key(default_func, keys);
  693         tmp = wchar_t2char(wtmp);
  694         snprintf(prompt_slk_message, strlen(buf) + 2, "%s%s", buf, tmp);
  695         FreeIfNeeded(tmp);
  696     }
  697 #else
  698     snprintf(prompt_slk_message, strlen(buf) + 2, "%s%c", buf, func_to_key(default_func, keys));
  699 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  700 
  701     input_context = cPromptSLK;
  702 
  703     do {
  704         prompt_slk_redraw();        /* draw the prompt */
  705 
  706 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  707         if ((ch = ReadWch()) == '\r' || ch == '\n')
  708 #else
  709         if ((ch = ReadCh()) == '\r' || ch == '\n')
  710 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  711             func = default_func;
  712         else
  713             func = key_to_func(ch, keys);
  714 
  715 #if 1
  716         /*
  717          * ignore special-keys which are represented as a multibyte ESC-seq
  718          * to avoid interpreting them as 'ESC' only
  719          */
  720         if (ch == ESC) {
  721             switch (get_arrow_key(ch)) {
  722                 case KEYMAP_UP:
  723                 case KEYMAP_DOWN:
  724                 case KEYMAP_LEFT:
  725                 case KEYMAP_RIGHT:
  726                 case KEYMAP_PAGE_DOWN:
  727                 case KEYMAP_PAGE_UP:
  728                 case KEYMAP_HOME:
  729                 case KEYMAP_END:
  730                     ch = '\0';
  731                     func = NOT_ASSIGNED;
  732                     break;
  733 
  734                 default:
  735                     break;
  736             }
  737         }
  738 #endif /* 1 */
  739     } while (func == NOT_ASSIGNED);
  740 
  741     input_context = cNone;
  742     FreeAndNull(prompt_slk_message);
  743 
  744     clear_message();
  745     return func;
  746 }
  747 
  748 
  749 /* (Re)draws the prompt message for prompt_slk_response() */
  750 void
  751 prompt_slk_redraw(
  752     void)
  753 {
  754     int column;
  755 
  756     wait_message(0, "%s", prompt_slk_message);
  757 
  758     /* get the cursor _just_ right */
  759     column = strwidth(prompt_slk_message) - 1;
  760     MoveCursor(cLINES, column);
  761 }
  762 
  763 
  764 /*
  765  * Wait until a key is pressed. We specify the <RETURN> key otherwise
  766  * pedants will point out that:
  767  * i)  There is no 'any' key on a keyboard
  768  * ii) CTRL, SHIFT etc don't work
  769  */
  770 void
  771 prompt_continue(
  772     void)
  773 {
  774     int ch;
  775     int save_signal_context = signal_context;
  776 
  777     cmd_line = TRUE;
  778     info_message(_(txt_return_key));
  779     signal_context = cMain;
  780     input_context = cPromptCONT;
  781 
  782     switch ((ch = ReadCh())) {
  783         case ESC:
  784 #   ifdef HAVE_KEY_PREFIX
  785         case KEY_PREFIX:
  786 #   endif /* HAVE_KEY_PREFIX */
  787             (void) get_arrow_key(ch);
  788             /* FALLTHROUGH */
  789 
  790         default:
  791             break;
  792     }
  793 
  794     input_context = cNone;
  795     signal_context = save_signal_context;
  796 
  797 #ifdef USE_CURSES
  798     my_fputc('\n', stdout);
  799 #endif /* USE_CURSES */
  800     cmd_line = FALSE;
  801 #ifdef USE_CURSES
  802     my_retouch();
  803 #endif /* USE_CURSES */
  804 }