diff options
Diffstat (limited to 'alpine/mailcmd.c')
-rw-r--r-- | alpine/mailcmd.c | 364 |
1 files changed, 310 insertions, 54 deletions
diff --git a/alpine/mailcmd.c b/alpine/mailcmd.c index 905ddb19..0dd4c50b 100644 --- a/alpine/mailcmd.c +++ b/alpine/mailcmd.c @@ -1,10 +1,6 @@ -#if !defined(lint) && !defined(DOS) -static char rcsid[] = "$Id: mailcmd.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $"; -#endif - /* * ======================================================================== - * Copyright 2013-2021 Eduardo Chappa + * Copyright 2013-2022 Eduardo Chappa * Copyright 2006-2009 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -111,9 +107,11 @@ SEARCHSET *visible_searchset(MAILSTREAM *, MSGNO_S *); int select_by_status(MAILSTREAM *, SEARCHSET **); int select_by_rule(MAILSTREAM *, SEARCHSET **); int select_by_thread(MAILSTREAM *, MSGNO_S *, SEARCHSET **); -char *choose_a_rule(int); +char *choose_a_rule(int, char *); +int rulenick_complete(int, char *, int); int select_by_keyword(MAILSTREAM *, SEARCHSET **); -char *choose_a_keyword(void); +char *choose_a_keyword(char *); +int keyword_complete(char *, int); int select_sort(struct pine *, int, SortOrder *, int *); int print_index(struct pine *, MSGNO_S *, int); @@ -332,10 +330,18 @@ static ESCKEY_S sel_size_opt[] = { {-1, 0, NULL, NULL} }; -static ESCKEY_S sel_key_opt[] = { +static ESCKEY_S sel_rule_opt[] = { {0, 0, NULL, NULL}, {ctrl('T'), 14, "^T", N_("To List")}, + {0, 0, NULL, NULL}, /* Reserved for TAB completion */ + {'!', '!', "!", N_("Not")}, + {-1, 0, NULL, NULL} +}; + +static ESCKEY_S sel_key_opt[] = { {0, 0, NULL, NULL}, + {ctrl('T'), 14, "^T", N_("To List")}, + {0, 0, NULL, NULL}, /* Reserved for TAB completion */ {'!', '!', "!", N_("Not")}, {-1, 0, NULL, NULL} }; @@ -367,11 +373,14 @@ int alpine_get_password(char *prompt, char *pass, size_t len) { int flags = F_ON(F_QUELL_ASTERISKS, ps_global) ? OE_PASSWD_NOAST : OE_PASSWD; + int rv; flags |= OE_DISALLOW_HELP; pass[0] = '\0'; - return optionally_enter(pass, + rv = optionally_enter(pass, -(ps_global->ttyo ? FOOTER_ROWS(ps_global) : 3), 0, len, prompt, NULL, NO_HELP, &flags); + if(rv == 1) ps_global->user_says_cancel = 1; + return rv; } int @@ -662,6 +671,8 @@ view_text: thrd = fetch_thread(stream, mn_m2raw(msgmap, new_msgno)); if(thrd && thrd->top) topthrd = fetch_thread(stream, thrd->top); + else + topthrd = NULL; if(topthrd) j = count_lflags_in_thread(stream, topthrd, msgmap, MN_NONE); @@ -1340,7 +1351,7 @@ get_out: if(del_count > 0L){ state->mangled_footer = 1; /* MAX_SCREEN_COLS+1 = sizeof(prompt) */ snprintf(prompt, sizeof(prompt), "UNexclude %ld message%s in %.*s", del_count, - plural(del_count), MAX_SCREEN_COLS+1-40, + plural(del_count), MAX_SCREEN_COLS+1-45, pretty_fn(state->cur_folder)); prompt[sizeof(prompt)-1] = '\0'; if(F_ON(F_FULL_AUTO_EXPUNGE, state) @@ -1718,6 +1729,7 @@ cmd_flag(struct pine *state, MSGNO_S *msgmap, int aopt) char *keyword_array[2]; int user_defined_flags = 0, mailbox_flags = 0; int directly_to_maint_screen = 0; + int use_maint_screen = F_ON(F_FLAG_SCREEN_DFLT, ps_global); long unflagged, flagged, flags, rawno; MESSAGECACHE *mc = NULL; KEYWORD_S *kw; @@ -1949,11 +1961,8 @@ go_again: else #endif { - int use_maint_screen; int keyword_shortcut = 0; - use_maint_screen = F_ON(F_FLAG_SCREEN_DFLT, ps_global); - if(!use_maint_screen){ /* * We're going to call cmd_flag_prompt(). We need @@ -2761,7 +2770,7 @@ save_prompt(struct pine *state, CONTEXT_S **cntxt, char *nfldr, size_t len_nfldr SaveDel *dela, SavePreserveOrder *prea) { int rc, ku = -1, n, flags, last_rc = 0, saveable_count = 0, done = 0; - int delindex, preindex, r; + int delindex = 0, preindex = 0, r; char prompt[6*MAX_SCREEN_COLS+1], *p, expanded[MAILTMPLEN]; char *buf = tmp_20k_buf; char shortbuf[200]; @@ -3255,7 +3264,7 @@ create_for_save_prompt(CONTEXT_S *context, char *folder, int sequence_sensitive) int cmd_expunge(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int agg) { - long del_count, prefilter_del_count; + long del_count, prefilter_del_count = 0; int we_cancel = 0, rv = 0; char prompt[MAX_SCREEN_COLS+1]; char *sequence; @@ -3587,12 +3596,12 @@ cmd_export(struct pine *state, MSGNO_S *msgmap, int qline, int aopt) { char filename[MAXPATH+1], full_filename[MAXPATH+1], *err; char nmsgs[80]; - int r, leading_nl, failure = 0, orig_errno, rflags = GER_NONE; + int r, leading_nl, failure = 0, orig_errno = 0, rflags = GER_NONE; int flags = GE_IS_EXPORT | GE_SEQ_SENSITIVE, rv = 0; ENVELOPE *env; MESSAGECACHE *mc; BODY *b; - long i, count = 0L, start_of_append, rawno; + long i, count = 0L, start_of_append = 0, rawno; gf_io_t pc; STORE_S *store; struct variable *vars = state ? ps_global->vars : NULL; @@ -3866,7 +3875,7 @@ cmd_export(struct pine *state, MSGNO_S *msgmap, int qline, int aopt) } ok = 0; - snprintf(dir, sizeof(dir), "%s.d", full_filename); + snprintf(dir, sizeof(dir), "%.*s.d", MAXPATH-2, full_filename); dir[sizeof(dir)-1] = '\0'; do { @@ -3887,7 +3896,7 @@ cmd_export(struct pine *state, MSGNO_S *msgmap, int qline, int aopt) goto fini; } - snprintf(dir, sizeof(dir), "%s.d_%s", full_filename, + snprintf(dir, sizeof(dir), "%.*s.d_%s", MAXPATH- (int) strlen(long2string((long) tries))-3, full_filename, long2string((long) tries)); dir[sizeof(dir)-1] = '\0'; break; @@ -3960,24 +3969,33 @@ cmd_export(struct pine *state, MSGNO_S *msgmap, int qline, int aopt) * and if so, we write a counter name in the file name, just before the * extension of the file, and separate it with an underscore. */ - snprintf(filename, sizeof(filename), "%s%s%s", dir, S_FILESEP, lfile); + snprintf(filename, sizeof(filename), "%.*s%.*s%.*s", (int) strlen(dir), dir, + (int) strlen(S_FILESEP), S_FILESEP, + MAXPATH - (int) strlen(dir) - (int) strlen(S_FILESEP), lfile); filename[sizeof(filename)-1] = '\0'; while((ok = can_access(filename, ACCESS_EXISTS)) == 0 && errs == 0){ - char *ext; - snprintf(filename, sizeof(filename), "%d", counter); - if(strlen(dir) + strlen(S_FILESEP) + strlen(lfile) + strlen(filename) + 2 - > sizeof(filename)){ + char *ext, count[MAXPATH+1]; + unsigned long total; + snprintf(count, sizeof(count), "%d", counter); + if((ext = strrchr(lfile, '.')) != NULL) + *ext = '\0'; + total = strlen(dir) + strlen(S_FILESEP) + strlen(lfile) + strlen(count) + 3 + + (ext ? strlen(ext+1) : 0); + if(total > sizeof(filename)){ dprint((2, "FAILED Att Export: name too long: %s\n", dir, S_FILESEP, lfile)); errs++; continue; } - if((ext = strrchr(lfile, '.')) != NULL) - *ext = '\0'; - snprintf(filename, sizeof(filename), "%s%s%s%s%d%s%s", - dir, S_FILESEP, lfile, - ext ? "_" : "", counter++, ext ? "." : "", ext ? ext+1 : ""); + snprintf(filename, sizeof(filename), "%.*s%.*s%.*s%.*s%.*d%.*s%.*s", + (int) strlen(dir), dir, (int) strlen(S_FILESEP), S_FILESEP, + (int) strlen(lfile), lfile, + ext ? 1 : 0, ext ? "_" : "", + (int) strlen(count), counter++, + ext ? 1 : 0, ext ? "." : "", + ext ? (int) (sizeof(filename) - total) : 0, + ext ? ext+1 : ""); filename[sizeof(filename)-1] = '\0'; } @@ -8266,11 +8284,11 @@ select_by_gm_content(MAILSTREAM *stream, MSGNO_S *msgmap, long int msgno, SEARCH int select_by_text(MAILSTREAM *stream, MSGNO_S *msgmap, long int msgno, SEARCHSET **limitsrch) { - int r, ku, type, we_cancel = 0, flags, rv, ekeyi = 0; + int r = '\0', ku, type, we_cancel = 0, flags, rv, ekeyi = 0; int not = 0, me = 0; - char sstring[80], tmp[128]; + char sstring[512], tmp[128]; char *p, *sval = NULL; - char buftmp[MAILTMPLEN], namehdr[80]; + char namehdr[80]; ESCKEY_S ekey[8]; ENVELOPE *env = NULL; HelpType help; @@ -8446,7 +8464,7 @@ select_by_text(MAILSTREAM *stream, MSGNO_S *msgmap, long int msgno, SEARCHSET ** flags = OE_APPEND_CURRENT | OE_KEEP_TRAILING_SPACE; r = optionally_enter(sstring, -FOOTER_ROWS(ps_global), 0, - 79, tmp, ekey, help, &flags); + sizeof(sstring), tmp, ekey, help, &flags); if(me && r == 0 && ((!not && strcmp(sstring, _(match_me))) || (not && strcmp(sstring, _(dont_match_me))))) me = 0; @@ -8848,7 +8866,7 @@ select_by_rule(MAILSTREAM *stream, SEARCHSET **limitsrch) { char rulenick[1000], *nick; PATGRP_S *patgrp; - int r, not = 0, we_cancel = 0, rflags = ROLE_DO_SRCH + int r, last_r = 0, not = 0, we_cancel = 0, rflags = ROLE_DO_SRCH | ROLE_DO_INCOLS | ROLE_DO_ROLES | ROLE_DO_SCORES @@ -8858,6 +8876,16 @@ select_by_rule(MAILSTREAM *stream, SEARCHSET **limitsrch) rulenick[0] = '\0'; ps_global->mangled_footer = 1; + if(F_ON(F_ENABLE_TAB_COMPLETE, ps_global)){ + sel_rule_opt[2].ch = TAB; + sel_rule_opt[2].rval = 15; + sel_rule_opt[2].name = "TAB"; + sel_rule_opt[2].label = N_("Complete"); + } + else{ + memset(&sel_rule_opt[2], 0, sizeof(sel_rule_opt[2])); + } + do{ int oe_flags; @@ -8866,11 +8894,11 @@ select_by_rule(MAILSTREAM *stream, SEARCHSET **limitsrch) sizeof(rulenick), not ? _("Rule to NOT match: ") : _("Rule to match: "), - sel_key_opt, NO_HELP, &oe_flags); + sel_rule_opt, NO_HELP, &oe_flags); if(r == 14){ /* select rulenick from a list */ - if((nick=choose_a_rule(rflags)) != NULL){ + if((nick=choose_a_rule(rflags, NULL)) != NULL){ strncpy(rulenick, nick, sizeof(rulenick)-1); rulenick[sizeof(rulenick)-1] = '\0'; fs_give((void **) &nick); @@ -8878,6 +8906,23 @@ select_by_rule(MAILSTREAM *stream, SEARCHSET **limitsrch) else r = 4; } + else if(r == 15){ + int n = rulenick_complete(rflags, rulenick, sizeof(rulenick)); + + if(n > 1 && last_r == 15 && !(oe_flags & OE_USER_MODIFIED)){ + /* double tab with multiple completions: select from list */ + if((nick=choose_a_rule(rflags, rulenick)) != NULL){ + strncpy(rulenick, nick, sizeof(rulenick)-1); + rulenick[sizeof(rulenick)-1] = '\0'; + fs_give((void **) &nick); + r = 0; + } + else + r = 4; + } + else if(n != 1) + Writechar(BELL, 0); + } else if(r == '!') not = !not; @@ -8891,8 +8936,9 @@ select_by_rule(MAILSTREAM *stream, SEARCHSET **limitsrch) } removing_leading_and_trailing_white_space(rulenick); + last_r = r; - }while(r == 3 || r == 4 || r == '!'); + }while(r == 3 || r == 4 || r == 15 || r == '!'); /* @@ -8934,16 +8980,21 @@ select_by_rule(MAILSTREAM *stream, SEARCHSET **limitsrch) /* * Allow user to choose a rule from their list of rules. * + * Args rflags -- Pattern types to choose from + * prefix -- Only list rules matching the given prefix + * * Returns an allocated rule nickname on success, NULL otherwise. */ char * -choose_a_rule(int rflags) +choose_a_rule(int rflags, char *prefix) { char *choice = NULL; char **rule_list, **lp; int cnt = 0; + int prefix_length = 0; PAT_S *pat; PAT_STATE pstate; + void (*redraw)(void) = ps_global->redrawer; if(!(nonempty_patterns(rflags, &pstate) && first_pattern(&pstate))){ q_status_message(SM_ORDER, 3, 3, @@ -8955,8 +9006,15 @@ choose_a_rule(int rflags) * Build a list of rules to choose from. */ - for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)) - cnt++; + if(prefix) + prefix_length = strlen(prefix); + + for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)) { + if(!pat->patgrp || !pat->patgrp->nick) + continue; + if(!prefix || strncmp(pat->patgrp->nick, prefix, prefix_length) == 0) + cnt++; + } if(cnt <= 0){ q_status_message(SM_ORDER, 3, 4, _("No rules defined, use Setup/Rules")); @@ -8966,9 +9024,12 @@ choose_a_rule(int rflags) lp = rule_list = (char **) fs_get((cnt + 1) * sizeof(*rule_list)); memset(rule_list, 0, (cnt+1) * sizeof(*rule_list)); - for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)) - *lp++ = cpystr((pat->patgrp && pat->patgrp->nick) - ? pat->patgrp->nick : "?"); + for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)) { + if(!pat->patgrp || !pat->patgrp->nick) + continue; + if(!prefix || strncmp(pat->patgrp->nick, prefix, prefix_length) == 0) + *lp++ = cpystr(pat->patgrp->nick); + } /* TRANSLATORS: SELECT A RULE is a screen title TRANSLATORS: Print something1 using something2. @@ -8977,8 +9038,10 @@ choose_a_rule(int rflags) _("rules"), h_select_rule_screen, _("HELP FOR SELECTING A RULE NICKNAME"), NULL); - if(!choice) + if(!choice){ q_status_message(SM_ORDER, 1, 4, "No choice"); + ps_global->redrawer = redraw; + } free_list_array(&rule_list); @@ -8987,6 +9050,80 @@ choose_a_rule(int rflags) /* + * Complete a partial rule name against the user's list of rules. + * + * Args rflags -- Pattern types to choose from + * nick -- Current rule nickname to complete + * nick_size -- Maximum length of the nick array to store completion in + * + * Returns the number of valid completions, i.e.: + * + * 0 if there are no valid completions. The value of the nick argument has not + * been changed. + * 1 if there is only a single valid completion. The value of the nick argument + * has been replaced with the full text of that completion. + * >1 if there is more than one valid completion. The value of the nick argument + * has been replaced with the longest substring common to all the appropriate + * completions. + */ +int +rulenick_complete(int rflags, char *nick, int nick_size) +{ + char *candidate = NULL; + int cnt = 0; + int common_prefix_length = 0; + int nick_length; + PAT_S *pat; + PAT_STATE pstate; + + if(!(nonempty_patterns(rflags, &pstate) && first_pattern(&pstate))) + return 0; + + nick_length = strlen(nick); + + for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){ + if(!pat->patgrp || !pat->patgrp->nick) + continue; + if(strncmp(pat->patgrp->nick, nick, nick_length) == 0){ + /* This is a candidate for completion. */ + cnt++; + if(!candidate){ + /* This is the first candidate. Keep it as a future reference to + * compare against to find the longest common prefix length of + * all the matches. */ + candidate = pat->patgrp->nick; + common_prefix_length = strlen(pat->patgrp->nick); + } + else{ + /* Find the common prefix length between the first candidate and + * this one. */ + int i; + for(i = 0; i < common_prefix_length; i++){ + if(pat->patgrp->nick[i] != candidate[i]){ + /* In the event that we ended up in the middle of a + * UTF-8 code point, backtrack to the byte before the + * start of this code point. */ + while(i > 0 && (candidate[i] & 0xC0) == 0x80) + i--; + common_prefix_length = i; + break; + } + } + } + } + } + + if(cnt > 0){ + int length = MIN(nick_size, common_prefix_length); + strncpy(nick + nick_length, candidate + nick_length, length - nick_length); + nick[length] = '\0'; + } + + return cnt; +} + + +/* * Select by current thread. * Sets searched bits in mail_elts for this entire thread * @@ -9038,7 +9175,7 @@ select_by_thread(MAILSTREAM *stream, MSGNO_S *msgmap, SEARCHSET **limitsrch) int select_by_keyword(MAILSTREAM *stream, SEARCHSET **limitsrch) { - int r, not = 0, we_cancel = 0; + int r, last_r = 0, not = 0, we_cancel = 0; char keyword[MAXUSERFLAG+1], *kword; char *error = NULL, *p, *prompt; HelpType help; @@ -9047,6 +9184,16 @@ select_by_keyword(MAILSTREAM *stream, SEARCHSET **limitsrch) keyword[0] = '\0'; ps_global->mangled_footer = 1; + if(F_ON(F_ENABLE_TAB_COMPLETE, ps_global)){ + sel_key_opt[2].ch = TAB; + sel_key_opt[2].rval = 15; + sel_key_opt[2].name = "TAB"; + sel_key_opt[2].label = N_("Complete"); + } + else{ + memset(&sel_key_opt[2], 0, sizeof(sel_key_opt[2])); + } + help = NO_HELP; do{ int oe_flags; @@ -9076,7 +9223,7 @@ select_by_keyword(MAILSTREAM *stream, SEARCHSET **limitsrch) if(r == 14){ /* select keyword from a list */ - if((kword=choose_a_keyword()) != NULL){ + if((kword=choose_a_keyword(NULL)) != NULL){ strncpy(keyword, kword, sizeof(keyword)-1); keyword[sizeof(keyword)-1] = '\0'; fs_give((void **) &kword); @@ -9084,6 +9231,23 @@ select_by_keyword(MAILSTREAM *stream, SEARCHSET **limitsrch) else r = 4; } + else if(r == 15){ + int n = keyword_complete(keyword, sizeof(keyword)); + + if(n > 1 && last_r == 15 && !(oe_flags & OE_USER_MODIFIED)){ + /* double tab with multiple completions: select from list */ + if((kword=choose_a_keyword(keyword)) != NULL){ + strncpy(keyword, kword, sizeof(keyword)-1); + keyword[sizeof(keyword)-1] = '\0'; + fs_give((void **) &kword); + r = 0; + } + else + r = 4; + } + else if(n != 1) + Writechar(BELL, 0); + } else if(r == '!') not = !not; @@ -9095,8 +9259,9 @@ select_by_keyword(MAILSTREAM *stream, SEARCHSET **limitsrch) } removing_leading_and_trailing_white_space(keyword); + last_r = r; - }while(r == 3 || r == 4 || r == '!' || keyword_check(keyword, &error)); + }while(r == 3 || r == 4 || r == 15 || r == '!' || keyword_check(keyword, &error)); if(F_ON(F_FLAG_SCREEN_KW_SHORTCUT, ps_global) && ps_global->keywords){ @@ -9152,22 +9317,32 @@ select_by_keyword(MAILSTREAM *stream, SEARCHSET **limitsrch) /* * Allow user to choose a keyword from their list of keywords. * + * Args prefix -- Only list keywords matching the given prefix + * * Returns an allocated keyword on success, NULL otherwise. */ char * -choose_a_keyword(void) +choose_a_keyword(char *prefix) { char *choice = NULL; char **keyword_list, **lp; int cnt; + int prefix_length = 0; KEYWORD_S *kw; + void (*redraw)(void) = ps_global->redrawer; /* * Build a list of keywords to choose from. */ - for(cnt = 0, kw = ps_global->keywords; kw; kw = kw->next) - cnt++; + if(prefix) + prefix_length = strlen(prefix); + + for(cnt = 0, kw = ps_global->keywords; kw; kw = kw->next){ + char *kw_name = kw->nick ? kw->nick : kw->kw; + if(!prefix || kw_name && strncmp(kw_name, prefix, prefix_length) == 0) + cnt++; + } if(cnt <= 0){ q_status_message(SM_ORDER, 3, 4, @@ -9178,8 +9353,13 @@ choose_a_keyword(void) lp = keyword_list = (char **) fs_get((cnt + 1) * sizeof(*keyword_list)); memset(keyword_list, 0, (cnt+1) * sizeof(*keyword_list)); - for(kw = ps_global->keywords; kw; kw = kw->next) - *lp++ = cpystr(kw->nick ? kw->nick : kw->kw ? kw->kw : ""); + for(kw = ps_global->keywords; kw; kw = kw->next){ + char *kw_name = kw->nick ? kw->nick : kw->kw; + if(!kw_name) + continue; + if(!prefix || kw_name && strncmp(kw_name, prefix, prefix_length) == 0) + *lp++ = cpystr(kw_name); + } /* TRANSLATORS: SELECT A KEYWORD is a screen title TRANSLATORS: Print something1 using something2. @@ -9188,8 +9368,10 @@ choose_a_keyword(void) _("keywords"), h_select_keyword_screen, _("HELP FOR SELECTING A KEYWORD"), NULL); - if(!choice) + if(!choice){ q_status_message(SM_ORDER, 1, 4, "No choice"); + ps_global->redrawer = redraw; + } free_list_array(&keyword_list); @@ -9198,6 +9380,77 @@ choose_a_keyword(void) /* + * Complete a partial keyword name against the user's list of keywords. + * + * Args keyword -- Current keyword to complete + * keyword_size -- Maximum length of the keyword array to store + * completion in + * + * Returns the number of valid completions, i.e.: + * + * 0 if there are no valid completions. The value of the keyword argument has + * not been changed. + * 1 if there is only a single valid completion. The value of the keyword + * argument has been replaced with the full text of that completion. + * >1 if there is more than one valid completion. The value of the keyword + * argument has been replaced with the longest substring common to all the + * appropriate completions. + */ +int +keyword_complete(char *keyword, int keyword_size) +{ + char *candidate = NULL; + int cnt = 0; + int common_prefix_length = 0; + int keyword_length; + KEYWORD_S *kw; + + keyword_length = strlen(keyword); + + for(kw = ps_global->keywords; kw; kw = kw->next){ + char *kw_name = kw->nick ? kw->nick : kw->kw; + if(!kw_name) + continue; + if(strncmp(kw_name, keyword, keyword_length) == 0){ + /* This is a candidate for completion. */ + cnt++; + if(!candidate){ + /* This is the first candidate. Keep it as a future reference to + * compare against to find the longest common prefix length of + * all the matches. */ + candidate = kw_name; + common_prefix_length = strlen(candidate); + } + else{ + /* Find the common prefix length between the first candidate and + * this one. */ + int i; + for(i = 0; i < common_prefix_length; i++){ + if(kw_name[i] != candidate[i]){ + /* In the event that we ended up in the middle of a + * UTF-8 code point, backtrack to the byte before the + * start of this code point. */ + while(i > 0 && (candidate[i] & 0xC0) == 0x80) + i--; + common_prefix_length = i; + break; + } + } + } + } + } + + if(cnt > 0){ + int length = MIN(keyword_size, common_prefix_length); + strncpy(keyword + keyword_length, candidate + keyword_length, length - keyword_length); + keyword[length] = '\0'; + } + + return cnt; +} + + +/* * Allow user to choose a list of keywords from their list of keywords. * * Returns allocated list. @@ -9268,6 +9521,7 @@ choose_a_charset(int which_charsets) char **charset_list, **lp; const CHARSET *cs; int cnt; + void (*redraw)(void) = ps_global->redrawer; /* * Build a list of charsets to choose from. @@ -9311,8 +9565,10 @@ choose_a_charset(int which_charsets) _("character sets"), h_select_charset_screen, _("HELP FOR SELECTING A CHARACTER SET"), NULL); - if(!choice) + if(!choice){ q_status_message(SM_ORDER, 1, 4, "No choice"); + ps_global->redrawer = redraw; + } free_list_array(&charset_list); |