"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.4/src/prompt.c" (20 Nov 2019, 19003 Bytes) of package /linux/misc/tin-2.4.4.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 "prompt.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.3_vs_2.4.4.

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