"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.2/src/prompt.c" (9 Dec 2022, 19790 Bytes) of package /linux/misc/tin-2.6.2.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.6.1_vs_2.6.2.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : prompt.c
    4  *  Author    : I. Lea
    5  *  Created   : 1991-04-01
    6  *  Updated   : 2021-10-29
    7  *  Notes     :
    8  *
    9  * Copyright (c) 1991-2023 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 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  183     yes = (wint_t) func_to_key(PROMPT_YES, prompt_keys);
  184     no = (wint_t) func_to_key(PROMPT_NO, prompt_keys);
  185 
  186     printascii(keyyes, (default_answer ? towupper(yes) : yes));
  187     printascii(keyno, (!default_answer ? towupper(no) : no));
  188 #else
  189     yes = func_to_key(PROMPT_YES, prompt_keys);
  190     no = func_to_key(PROMPT_NO, prompt_keys);
  191 
  192     printascii(keyyes, (default_answer ? my_toupper(yes) : yes));
  193     printascii(keyno, (!default_answer ? my_toupper(no) : no));
  194 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  195 
  196     keyyes_len = strwidth(keyyes);
  197     keyno_len = strwidth(keyno);
  198     maxlen = MAX(keyyes_len, keyno_len);
  199     prompt_len = keyyes_len + keyno_len + maxlen + 6;
  200     prompt_yn_message = my_strdup(prompt);
  201     prompt_yn_choice = my_malloc(prompt_len + 1);
  202 
  203     input_context = cPromptYN;
  204 
  205     do {
  206         prompt_ch = (default_answer ? yes : no);
  207         keyprompt = (default_answer ? keyyes : keyno);
  208 
  209         snprintf(prompt_yn_choice, (size_t) prompt_len, " (%s/%s) %-*s", keyyes, keyno, maxlen, keyprompt);
  210         prompt_yn_redraw();
  211 
  212 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  213         if (((ch = ReadWch()) == '\n') || (ch == '\r'))
  214 #else
  215         if (((ch = (char) ReadCh()) == '\n') || (ch == '\r'))
  216 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  217             ch = prompt_ch;
  218 
  219         switch (ch) {
  220             case ESC:   /* (ESC) common arrow keys */
  221 #ifdef HAVE_KEY_PREFIX
  222             case KEY_PREFIX:
  223 #endif /* HAVE_KEY_PREFIX */
  224                 switch (get_arrow_key((int) ch)) {
  225                     case KEYMAP_UP:
  226                     case KEYMAP_DOWN:
  227                         default_answer = bool_not(default_answer);
  228                         ch = '\0';  /* set to a not bindable key to not leave the loop yet */
  229                         break;
  230 
  231                     case KEYMAP_LEFT:
  232                         ch = ESC;
  233                         break;
  234 
  235                     case KEYMAP_RIGHT:
  236                         ch = prompt_ch;
  237                         break;
  238 
  239                     default:
  240                         break;
  241                 }
  242                 break;
  243 
  244             default:
  245                 break;
  246         }
  247         func = key_to_func((wchar_t) ch, prompt_keys);
  248     } while (func == NOT_ASSIGNED);
  249 
  250     input_context = cNone;
  251     FreeAndNull(prompt_yn_message);
  252     FreeAndNull(prompt_yn_choice);
  253 
  254     if (!cmd_line) {
  255         clear_message();
  256         my_flush();
  257     }
  258     return (func == PROMPT_YES) ? 1 : (func == GLOBAL_ABORT) ? -1 : 0;
  259 }
  260 
  261 
  262 /*
  263  * (Re)draws and resize the prompt message for prompt_yn()
  264  */
  265 void
  266 prompt_yn_redraw(
  267     void)
  268 {
  269     char *buf;
  270     int choice_len = strwidth(prompt_yn_choice);
  271     int message_len = strwidth(prompt_yn_message);
  272 
  273     if (!cmd_line) {
  274         MoveCursor(cLINES, 0);
  275         CleartoEOLN();
  276     }
  277     if (message_len + choice_len > cCOLS - 1) {
  278         buf = strunc(prompt_yn_message, cCOLS - choice_len - 1);
  279         message_len = strwidth(buf);
  280         my_printf("%s%s", buf, prompt_yn_choice);
  281         free(buf);
  282     } else
  283         my_printf("%s%s", prompt_yn_message, prompt_yn_choice);
  284 
  285     if (!cmd_line)
  286         cursoron();
  287     my_flush();
  288     if (!cmd_line)
  289         MoveCursor(cLINES, (message_len + choice_len) - 1);
  290 }
  291 
  292 
  293 /*
  294  * help_text is displayed near the bottom of the screen.
  295  * var is an index into a list containing size elements.
  296  * The text from list is shown at row, col + len(prompt_text)
  297  * Choice is incremented using the space bar, wrapping to 0
  298  * ESC is used to abort any changes, RET saves changes.
  299  * The new value is returned.
  300  */
  301 static int
  302 prompt_list(
  303     int row,
  304     int col,
  305     int var,
  306     constext *help_text,
  307     constext *prompt_text,
  308     constext *list[],
  309     int size)
  310 {
  311     int ch, var_orig;
  312     int i, offset, width = 0;
  313     int change;
  314     int adjust = (strcasecmp(_(list[0]), _(txt_default)) == 0);
  315 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  316     char *buf;
  317 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  318 
  319     var += adjust;
  320     var_orig = var;
  321 
  322     /*
  323      * Find the length of longest printable text
  324      */
  325     for (i = 0; i < size; i++)
  326         width = MAX(width, strwidth(_(list[i])));
  327 
  328     show_menu_help(help_text);
  329     cursoron();
  330 
  331     offset = strwidth(_(prompt_text));
  332 
  333     /*
  334      * Make sure to not exceed cCOLS
  335      */
  336     if (offset + width >= cCOLS)
  337         width = cCOLS - offset - 1;
  338 
  339     do {
  340         MoveCursor(row, col + offset);
  341         ch = (char) ReadCh();
  342 
  343         /*
  344          * change:
  345          *   1 = move to the next list element
  346          *   0 = do nothing
  347          *  -1 = move to the previous list element
  348          *
  349          *  if an arrow key was pressed change ch to another value
  350          *  otherwise we will exit the while loop
  351          */
  352         switch (ch) {
  353             case ' ':
  354                 change = 1;
  355                 break;
  356 
  357             case ESC:   /* (ESC) common arrow keys */
  358 #ifdef HAVE_KEY_PREFIX
  359             case KEY_PREFIX:
  360 #endif /* HAVE_KEY_PREFIX */
  361                 switch (get_arrow_key(ch)) {
  362                     case KEYMAP_UP:
  363                         change = -1;
  364                         ch = ' ';
  365                         break;
  366 
  367                     case KEYMAP_DOWN:
  368                         change = 1;
  369                         ch = ' ';
  370                         break;
  371 
  372                     default:
  373                         change = 0;
  374                         break;
  375                 }
  376                 break;
  377 
  378             default:
  379                 change = 0;
  380                 break;
  381         }
  382 
  383         if (change) {
  384             /*
  385              * increment or decrement list, loop around at the limits
  386              */
  387             var += change;
  388             if (var < 0)
  389                 var = size - 1;
  390             else
  391                 var %= (size ? size : 1);
  392 
  393 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  394             if ((buf = spart(_(list[var]), width, TRUE)) != NULL) {
  395                 my_printf("%s", buf);
  396                 free(buf);
  397             } else
  398 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  399                 my_printf("%-*s", width, _(list[var]));
  400             my_flush();
  401         }
  402     } while (ch != '\r' && ch != '\n' && ch != ESC);
  403 
  404     if (ch == ESC) {
  405         var = var_orig;
  406 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  407         if ((buf = spart(_(list[var]), width, TRUE)) != NULL) {
  408             my_printf("%s", buf);
  409             free(buf);
  410         } else
  411 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  412             my_printf("%-*s", width, _(list[var]));
  413         my_flush();
  414     }
  415 
  416     cursoroff();
  417     return (var - adjust);
  418 }
  419 
  420 
  421 /*
  422  * Special case of prompt_option_list() Toggle between ON and OFF
  423  * The function returns TRUE, if the value was changed, FALSE otherwise.
  424  */
  425 t_bool
  426 prompt_option_on_off(
  427     enum option_enum option)
  428 {
  429     char prompt[LEN];
  430     t_bool *variable = OPT_ON_OFF_list[option_table[option].var_index];
  431     t_bool old_value = *variable;
  432 
  433     fmt_option_prompt(prompt, sizeof(prompt), TRUE, option);
  434     *variable = prompt_list(option_row(option), 0, (int) *variable, option_table[option].txt->help, prompt, txt_onoff, 2) ? TRUE : FALSE;
  435     return bool_not(bool_equal(*variable, old_value));
  436 }
  437 
  438 
  439 /*
  440  * The function returns TRUE, if the value was changed, FALSE otherwise.
  441  */
  442 t_bool
  443 prompt_option_list(
  444     enum option_enum option)
  445 {
  446     char prompt[LEN];
  447     int *variable = option_table[option].variable;
  448     int old_value = *variable;
  449     int opt_count = 0;
  450 
  451     while (option_table[option].opt_list[opt_count] != NULL)
  452         ++opt_count;
  453     fmt_option_prompt(prompt, sizeof(prompt), TRUE, option);
  454     *variable = prompt_list(option_row(option), 0, *variable, option_table[option].txt->help, prompt, option_table[option].opt_list, opt_count);
  455     return *variable != old_value;
  456 }
  457 
  458 
  459 /*
  460  * Displays option text and actual option value for string based options in
  461  * one line, help text for that option near the bottom of the screen. Allows
  462  * change of the old value by normal editing; history function of tin_getline()
  463  * will be used properly so that editing won't leave the actual line.
  464  *
  465  * The function returns TRUE, if the value was changed, FALSE otherwise.
  466  */
  467 t_bool
  468 prompt_option_string(
  469     enum option_enum option) /* return value is always ignored */
  470 {
  471     char *variable = OPT_STRING_list[option_table[option].var_index];
  472     char prompt[LEN];
  473     char old_value[LEN];
  474 
  475     STRCPY(old_value, variable);
  476     show_menu_help(option_table[option].txt->help);
  477     fmt_option_prompt(prompt, sizeof(prompt) - 1, TRUE, option);
  478     if (prompt_menu_string(option_row(option), prompt, variable))
  479         return strcmp(old_value, variable) ? TRUE : FALSE;
  480     else
  481         return FALSE;
  482 }
  483 
  484 
  485 /*
  486  * Displays option text and current option value for number based options in
  487  * one line, help text for that option near the bottom of the screen. Allows
  488  * change of the old value by normal editing; history function of tin_getline()
  489  * will be used properly so that editing won't leave the current line.
  490  *
  491  * The function returns TRUE if the value was changed, FALSE otherwise.
  492  */
  493 t_bool
  494 prompt_option_num(
  495     enum option_enum option) /* return value is always ignored */
  496 {
  497     char prompt[LEN];
  498     char number[LEN];
  499     char *p;
  500     int num;
  501 
  502     show_menu_help(option_table[option].txt->help);
  503     MoveCursor(option_row(option), 0);
  504     fmt_option_prompt(prompt, sizeof(prompt) - 1, TRUE, option);
  505     snprintf(&number[0], sizeof(number), "%d", *(option_table[option].variable));
  506 
  507     if ((p = tin_getline(prompt, 2, number, 0, FALSE, HIST_OTHER)) == NULL)
  508         return FALSE;
  509 
  510     STRCPY(number, p);
  511     num = atoi(number);
  512     *(option_table[option].variable) = num;
  513     clear_message();
  514     return TRUE;
  515 }
  516 
  517 
  518 /*
  519  * Displays option text and actual option value for character based options
  520  * in one line, help text for that option near the bottom of the screen.
  521  * Allows change of the old value by normal editing.
  522  *
  523  * The function returns TRUE if the value was changed, FALSE otherwise.
  524  */
  525 t_bool
  526 prompt_option_char(
  527     enum option_enum option) /* return value is always ignored */
  528 {
  529     char prompt[LEN];
  530 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  531     wchar_t input[2];
  532     wchar_t *variable = OPT_CHAR_list[option_table[option].var_index];
  533     int max_chars = (int) sizeof(wchar_t) + 1;
  534     wchar_t *wp;
  535     char *p;
  536     char *curr_val;
  537 #else
  538     char input[2];
  539     char *variable = OPT_CHAR_list[option_table[option].var_index];
  540     char *p;
  541     char *curr_val = &input[0];
  542     int max_chars = 1;
  543 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  544 
  545     input[0] = *variable;
  546     input[1] = '\0';
  547 
  548 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  549     if ((curr_val = wchar_t2char(input))) {
  550 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  551 
  552     do {
  553         show_menu_help(option_table[option].txt->help);
  554         MoveCursor(option_row(option), 0);
  555         fmt_option_prompt(prompt, sizeof(prompt) - 1, TRUE, option);
  556 
  557         if ((p = tin_getline(prompt, 0, curr_val, max_chars, FALSE, HIST_OTHER)) == NULL) {
  558             clear_message();
  559             return FALSE;
  560         }
  561         if (!*p)
  562             info_message(_(txt_info_enter_valid_character));
  563     } while (!*p);
  564 
  565 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  566         if ((wp = char2wchar_t(p))) {
  567             *variable = wp[0];
  568             free(wp);
  569         }
  570         free(curr_val);
  571     }
  572 #else
  573     *variable = p[0];
  574 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  575 
  576     clear_message();
  577     return TRUE;
  578 }
  579 
  580 
  581 /*
  582  * Get a string. Make it the new default.
  583  * If none given, use the default.
  584  * Return the string or NULL if we can't get anything useful
  585  */
  586 char *
  587 prompt_string_default(
  588     const char *prompt,
  589     char *def,
  590     const char *failtext,
  591     int history)
  592 {
  593     char pattern[LEN];
  594 
  595     clear_message();
  596 
  597     if (!prompt_string(prompt, pattern, history)) {
  598         clear_message();
  599         return NULL;
  600     }
  601 
  602     if (pattern[0] != '\0')         /* got a string - make it the default */
  603         my_strncpy(def, pattern, LEN);
  604     else {
  605         if (def[0] == '\0') {       /* no default - give up */
  606             error_message(2, "%s", failtext);
  607             return NULL;
  608         }
  609     }
  610 
  611     return def;                 /* use the default */
  612 }
  613 
  614 
  615 /*
  616  * Get a message ID for the 'L' command. Add <> if needed
  617  * If the msgid exists and is reachable, return its index
  618  * in arts[], else ART_UNAVAILABLE
  619  */
  620 int
  621 prompt_msgid(
  622     void)
  623 {
  624     char buf[LEN];
  625 
  626     if (prompt_string(_(txt_enter_message_id), buf + 1, HIST_MESSAGE_ID) && buf[1]) {
  627         char *ptr = str_trim(buf + 1);
  628         struct t_msgid *msgid;
  629 
  630         /*
  631          * If the user failed to supply Message-ID in <>, add them
  632          */
  633         if (buf[1] != '<') {
  634             buf[0] = '<';
  635             strcat(buf, ">");
  636             ptr = buf;
  637         }
  638 
  639         if ((msgid = find_msgid(ptr)) == NULL) {
  640             info_message(_(txt_art_unavailable));
  641             return ART_UNAVAILABLE;
  642         }
  643 
  644         /*
  645          * Is it expired or otherwise not on the spool ?
  646          */
  647         if (msgid->article == ART_UNAVAILABLE) {
  648             info_message(_(txt_art_unavailable));
  649             return ART_UNAVAILABLE;
  650         }
  651 
  652         /*
  653          * If the article is no longer part of a thread, then there is
  654          * no way to display it
  655          */
  656         if (which_thread(msgid->article) == -1) {
  657             info_message(_(txt_no_last_message));
  658             return ART_UNAVAILABLE;
  659         }
  660 
  661         return msgid->article;
  662     }
  663 
  664     return ART_UNAVAILABLE;
  665 }
  666 
  667 
  668 /*
  669  * Format a message such that it'll fit within the screen width
  670  * Useful for fitting long Subjects and newsgroup names into prompts
  671  * result will contain a pointer to the malloced memory containing the
  672  * sized message
  673  */
  674 char *
  675 sized_message(
  676     char **result,
  677     const char *format,
  678     const char *subject)
  679 {
  680     char *buf;
  681     int max_len;
  682 
  683     max_len = cCOLS - strwidth(format) + 2 - 1; /* The formatting info (%s) wastes 2 chars, but our prompt needs 1 char */
  684 
  685     buf = strunc(subject, max_len);
  686 
  687     *result = fmt_string(format, buf);
  688     free(buf);
  689 
  690     return *result;
  691 }
  692 
  693 
  694 /*
  695  * Implement the Single-Letter-Key mini menus at the bottom of the screen
  696  * eg, Press a)ppend, o)verwrite, q)uit :
  697  */
  698 t_function
  699 prompt_slk_response(
  700     t_function default_func,
  701     const struct keylist keys,
  702     const char *fmt,
  703     ...)
  704 {
  705     va_list ap;
  706     char buf[LEN];
  707     t_function func;
  708 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  709     wchar_t ch;
  710 #else
  711     char ch;
  712 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  713 
  714     va_start(ap, fmt);
  715     vsnprintf(buf, sizeof(buf), fmt, ap);
  716     va_end(ap);
  717 
  718     prompt_slk_message = my_malloc(strlen(buf) + 2);
  719 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  720     {
  721         char *tmp;
  722         wchar_t wtmp[2] = { '\0', '\0' };
  723 
  724         wtmp[0] = func_to_key(default_func, keys);
  725         tmp = wchar_t2char(wtmp);
  726         snprintf(prompt_slk_message, strlen(buf) + 2, "%s%s", buf, tmp);
  727         FreeIfNeeded(tmp);
  728     }
  729 #else
  730     snprintf(prompt_slk_message, strlen(buf) + 2, "%s%c", buf, func_to_key(default_func, keys));
  731 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  732 
  733     input_context = cPromptSLK;
  734 
  735     do {
  736         prompt_slk_redraw();        /* draw the prompt */
  737 
  738 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  739         if ((ch = (wchar_t) ReadWch()) == '\r' || ch == '\n')
  740 #else
  741         if ((ch = ReadCh()) == '\r' || ch == '\n')
  742 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  743             func = default_func;
  744         else
  745             func = key_to_func(ch, keys);
  746 
  747 #if 1
  748         /*
  749          * ignore special-keys which are represented as a multibyte ESC-seq
  750          * to avoid interpreting them as 'ESC' only
  751          */
  752         if (ch == ESC) {
  753             switch (get_arrow_key(ch)) {
  754                 case KEYMAP_UP:
  755                 case KEYMAP_DOWN:
  756                 case KEYMAP_LEFT:
  757                 case KEYMAP_RIGHT:
  758                 case KEYMAP_PAGE_DOWN:
  759                 case KEYMAP_PAGE_UP:
  760                 case KEYMAP_HOME:
  761                 case KEYMAP_END:
  762                     ch = '\0';
  763                     func = NOT_ASSIGNED;
  764                     break;
  765 
  766                 default:
  767                     break;
  768             }
  769         }
  770 #endif /* 1 */
  771     } while (func == NOT_ASSIGNED);
  772 
  773     input_context = cNone;
  774     FreeAndNull(prompt_slk_message);
  775 
  776     clear_message();
  777     return func;
  778 }
  779 
  780 
  781 /* (Re)draws the prompt message for prompt_slk_response() */
  782 void
  783 prompt_slk_redraw(
  784     void)
  785 {
  786     int column;
  787 
  788     wait_message(0, "%s", prompt_slk_message);
  789 
  790     /* get the cursor _just_ right */
  791     column = strwidth(prompt_slk_message) - 1;
  792     MoveCursor(cLINES, column);
  793 }
  794 
  795 
  796 /*
  797  * Wait until a key is pressed. We specify the <RETURN> key otherwise
  798  * pedants will point out that:
  799  * i)  There is no 'any' key on a keyboard
  800  * ii) CTRL, SHIFT etc don't work
  801  */
  802 void
  803 prompt_continue(
  804     void)
  805 {
  806     int ch;
  807     int save_signal_context = signal_context;
  808 
  809     cmd_line = TRUE;
  810     info_message(_(txt_return_key));
  811     signal_context = cMain;
  812     input_context = cPromptCONT;
  813 
  814     switch ((ch = ReadCh())) {
  815         case ESC:
  816 #ifdef HAVE_KEY_PREFIX
  817         case KEY_PREFIX:
  818 #endif /* HAVE_KEY_PREFIX */
  819             (void) get_arrow_key(ch);
  820             /* FALLTHROUGH */
  821 
  822         default:
  823             break;
  824     }
  825 
  826     input_context = cNone;
  827     signal_context = save_signal_context;
  828 
  829 #ifdef USE_CURSES
  830     my_fputc('\n', stdout);
  831 #endif /* USE_CURSES */
  832     cmd_line = FALSE;
  833 #ifdef USE_CURSES
  834     my_retouch();
  835 #endif /* USE_CURSES */
  836 }